一家前端远程实习公司的笔试题分享📑

引言💭

记录我的第一场笔试。

专业相关基础题📑

1. Vue.js的生命周期函数及其执行顺序

Vue.js的生命周期函数可以分为以下几个阶段:

  • 创建阶段

    1. beforeCreate: 实例初始化之后,数据观测和事件配置之前。
    2. created: 实例已经创建完成,数据观测和事件配置已经完成,但DOM尚未渲染。
  • 挂载阶段

    1. beforeMount: 在挂载开始之前,相关的render函数首次被调用。
    2. mounted: 挂载完成后,DOM已插入页面中。
  • 更新阶段

    1. beforeUpdate: 数据变化导致视图更新之前。
    2. updated: 数据变化导致视图更新之后。
  • 销毁阶段

    1. beforeDestroy: 实例销毁之前。
    2. destroyed: 实例销毁之后。

顺序:beforeCreate -> created -> beforeMount -> mounted -> beforeUpdate -> updated -> beforeDestroy -> destroyed

2. v-bind指令和v-model指令的区别

  • v-bind :动态绑定一个属性到元素上。可以用于绑定任意一个属性值,常见用法有绑定 hrefclassstyle 等。

    ini 复制代码
    <a v-bind:href="url">链接</a>
  • v-model :用于实现双向绑定,通常用于表单元素如 <input>, <select>, <textarea>。它会根据控件类型自动绑定相应的事件和属性。

    ini 复制代码
    <input v-model="message">

区别v-bind 主要用于单向绑定,v-model 实现双向绑定,并且主要用于表单控件。

3. Vue的组件通信方式

详细可看我的另一篇文章:组件通信的九种方式

4. Vue中的响应式原理

Vue.js通过 Object.defineProperty (Vue 2.x) 或 Proxy (Vue 3.x) 实现数据的响应式。当你访问一个数据属性时,Vue会触发 getter 方法;当你修改数据时,Vue会触发 setter 方法,进而通知依赖该数据的视图更新。

Vue 3 使用 Proxy,提供了更加高效和灵活的响应式系统,支持嵌套的对象和数组。

5. 如何在Vue中实现路由跳转

编程式导航

  1. 选项式API
php 复制代码
   export default {
   methods: {
   navigate() {
     // 字符串路径
     this.$router.push('/about')
     
     // 对象形式
     this.$router.push({ path: '/about' })
     
     // 命名路由
     this.$router.push({ name: 'about' })
     
     // 带参数
     this.$router.push({ name: 'user', params: { id: '123' } })
     
     // 带查询参数
     this.$router.push({ path: '/search', query: { q: 'vue' } })
     
     // 替换当前路由
     this.$router.replace({ path: '/home' })
     
     // 前进/后退
     this.$router.go(1)  // 前进一步
     this.$router.go(-1) // 后退一步
     }
    }
   }
  1. 组合式API
xml 复制代码
<script setup>
import { useRouter } from 'vue-router'

const router = useRouter()

const navigate = () => {
  // 基本跳转
  router.push('/about')
  
  // 命名路由带参数
  router.push({
    name: 'user',
    params: { id: 123 }
  })
  
  // 替换当前路由
  router.replace('/login')
  
  // 前进/后退
  router.go(1)
  router.back() // 等同于 router.go(-1)
  router.forward() // 等同于 router.go(1)
}
</script>

声明式导航

  • 使用<router-link>组件
xml 复制代码
        <template>
        <!-- 基本用法 -->
        <router-link to="/">首页</router-link>

        <!-- 动态路径 -->
        <router-link :to="'/user/' + userId">用户页面</router-link>

        <!-- 命名路由 -->
        <router-link :to="{ name: 'user', params: { id: 123 }}">用户详情</router-link>

        <!-- 带查询参数 -->
        <router-link :to="{ path: '/search', query: { q: 'vue' }}">搜索</router-link>

        <!-- 替换当前路由(不记录历史) -->
        <router-link :to="..." replace>替换</router-link>

        <!-- 自定义激活类名 -->
        <router-link :to="..." active-class="active-link">链接</router-link>
        </template>

6. Vue.js中的computed和watch有什么区别

  • computed:计算属性,基于依赖的响应式数据缓存,只有当依赖数据发生变化时才会重新计算。

    kotlin 复制代码
    computed: {
      fullName() {
        return this.firstName + ' ' + this.lastName;
      }
    }
  • watch:观察属性,监听响应式数据变化时,执行指定的函数。

    javascript 复制代码
    watch: {
      message(newVal, oldVal) {
        console.log('message changed from', oldVal, 'to', newVal);
      }
    }

区别computed用于返回计算的结果,watch用于处理副作用操作(如异步请求等)。

7. Vue.js中的v-for指令和v-if指令有什么区别

  • v-for:用于循环渲染一个数组或对象。

    css 复制代码
    <div v-for="item in items" :key="item.id">{{ item.name }}</div>
  • v-if:用于根据条件渲染 DOM 元素。

    ini 复制代码
    <div v-if="isVisible">This will be shown if isVisible is true.</div>

区别

v-for是用来渲染列表,v-if是用来条件渲染元素。

  • Vue 2.x:v-for 优先级高于 v-if
  • Vue 3.x:v-if 优先级高于 v-for(在 Vue 3 中,这种用法会在控制台发出警告)

v-if不建议与v-for一起使用,因为它们会在不同的阶段运行,容易造成性能问题。

8. Vue.js中的mixins和extends的作用及其区别

  • mixins :用于封装可复用的代码块,可以将多个功能逻辑分离并共享到组件中。每个组件可以声明多个 mixins

    ini 复制代码
    mixins: [myMixin]
  • extends:用于将一个组件扩展为另一个组件,相当于继承。

    makefile 复制代码
    extends: ParentComponent

区别mixins可以用于多个组件共享某些功能,而extends更多用于继承父组件的行为。

9. Vue.js中的keep-alive组件有什么作用

keep-alive 是 Vue.js 的一个内置组件,主要用于缓存组件状态,让组件在切换时不会被销毁,从而保留数据和状态。

核心作用

  • 保存组件状态:缓存不活动的组件,避免重复渲染
  • 提升性能:减少组件销毁和重建的开销
  • 保持数据:如表单输入内容、滚动位置等不会丢失

基本使用方式

html 复制代码
<keep-alive>
  <component :is="currentComponent"></component>
</keep-alive>

常用功能

  1. 指定缓存组件:

    html 复制代码
    <keep-alive include="Home,About">
      <router-view></router-view>
    </keep-alive>
  2. 特殊生命周期:

    • activated() - 组件被激活时调用
    • deactivated() - 组件被缓存时调用
  3. 限制缓存数量:

    html 复制代码
    <keep-alive :max="5">
      <router-view></router-view>
    </keep-alive>

逻辑推理题🤔

1. 毒蘑菇

现在有1011种蘑菇,其中1种是毒蘑菇。人一旦吃了微量的毒蘑菇,就会在72小时后发作身亡。现在用松鼠做试验,从开始喂松鼠计时,要在72小时后马上找出毒蘑菇,问最少需要多少只松鼠?(需要给出解题过程)

关键信息

  1. 蘑菇总数:1011种,其中1种是有毒的。
  2. 毒蘑菇的特性:即使微量,食用后也会在72小时后发作身亡。
  3. 实验对象:松鼠。可以给松鼠喂食蘑菇。
  4. 时间限制:必须在72小时后立即确定出毒蘑菇。这意味着我们只有一次观察松鼠生死的机会。
  5. 目标:找出最少需要多少只松鼠,才能在72小时后唯一确定毒蘑菇。

解题思路

这个问题类似于经典的"毒药与老鼠"问题,其中需要通过实验设计在有限的资源(老鼠或松鼠)下,通过它们的生死状态来唯一标识出有毒的物品(蘑菇)。

在这种类型的问题中,通常使用二进制编码的方法来解决。具体步骤如下:

  1. 编码:将每一种蘑菇分配一个独特的二进制编码。
  2. 分配:根据编码,决定哪些松鼠会吃哪些蘑菇。具体来说,如果某一位是1,对应的松鼠会吃这种蘑菇;如果是0,则不吃。
  3. 观察:72小时后,观察哪些松鼠死亡。死亡的松鼠对应的位为1,存活的为0。将这些信息组合起来,就能得到毒蘑菇的二进制编码。
  4. 解码:根据松鼠的生死模式,解码出毒蘑菇的编号。

计算所需松鼠的数量

关键在于确定需要多少位二进制数才能唯一表示1011种蘑菇。因为每一种蘑菇需要一个独特的编码,而n位二进制可以表示2^n个不同的数。

我们需要找到最小的n,使得:

2^n ≥ 1011

计算:

  • 2^10 = 1024
  • 2^9 = 512

1024 > 1011 > 512,因此需要10位二进制数。

总结

最少需要10只松鼠

2. 帽子的颜色

在一个房间里, 有4个戴了帽子的小朋友, 4顶帽子的颜色为2个黑色2个白色,4个小朋友从左至右编号为1号、2号、3号、4号。如下图所示,其中1号和2号、3号、4号中间隔了一道墙,4个小朋友都只能向前看,看不到身后,彼此都无法看到墙对面的情况。

现在同时向四人提问:你头上戴的帽子是什么颜色的?

其他条件:

  • 四人都知道帽子有2个黑色、2个白色,但看不到自己头上帽子的颜色;
  • 站在台阶上的小朋友可以看到自己台阶下面所有小朋友的帽子颜色;
  • 四人不能讨论,但可以听见其他人的回答;
  • 四人都绝顶聪明;
  • 知道自己头上帽子颜色的,必须第一时间喊出自己头上帽子的颜色;
  • 如果不能确定自己头上帽子颜色,则不允许出声说话。

请问:是谁最先喊出自己帽子的颜色?

解题步骤

我们需要模拟每个小朋友的视角和推理过程。关键在于:

  • 从能看到最多信息的小朋友开始推理(这里是4号,可以看到2号/3号)。

  • 如果4号不立刻回答,说明ta无法直接确定,这会给其他人提供信息。

  • 依次向下推理(3号、2号、1号)。

4号视角

4号可以看见2号和3号的帽子为1白1黑,剩1白1黑,不能确定自己头上帽子的颜色,不能出声。

3号视角

3号可以看见2号的帽子为1白,根据4号没有出声可以推断出自己和2号帽子颜色不一致,则可以推断出自己帽子颜色为黑色

则是3号最先喊出自己帽子的颜色。

2号视角

2号不能看见任何一个人的帽子颜色,ta只能知道自己和3号帽子颜色不一致。

1号视角

1号也不能看见任何一个人的帽子颜色,并且ta也不能收获任何信息。

总结

3号最先喊出自己帽子的颜色。


算法题✍🏻

数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 '.' 表示。

方法思路

通过遍历整个数独棋盘,使用三个数组(rowscolsboxes)分别记录每行、每列和每个 3x3 子数独区域中出现过的数字,并且在检查每个数字时确保该数字没有在相应的行、列和子数独区域中重复出现。如果发现重复,就立即返回 false;如果遍历完没有问题,返回 true

代码

javascript 复制代码
/**
 * @param {character[][]} board
 * @return {boolean}
 */
var isValidSudoku = function(board) {
    // 初始化行、列和子数独的记录数组
    const rows = Array.from({ length: 9 }, () => ({}));
    const cols = Array.from({ length: 9 }, () => ({}));
    const boxes = Array.from({ length: 9 }, () => ({}));

    for (let i = 0; i < 9; i++) {
        for (let j = 0; j < 9; j++) {
            const cell = board[i][j];
            if (cell === '.') continue; // 跳过空格

            const num = parseInt(cell, 10);
            const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3); // 计算子数独索引

            // 检查当前数字是否已在行、列或子数独中出现
            if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {
                return false;
            }

            // 标记当前数字在行、列和子数独中已出现
            rows[i][num] = true;
            cols[j][num] = true;
            boxes[boxIndex][num] = true;
        }
    }
    return true; // 所有检查通过,数独有效
};

代码解释

1. 初始化数据结构
ini 复制代码
const rows = Array.from({ length: 9 }, () => ({}));
const cols = Array.from({ length: 9 }, () => ({}));
const boxes = Array.from({ length: 9 }, () => ({}));
  • rowscolsboxes 都是长度为 9 的数组,其中每个元素是一个空对象。分别用来记录每行、每列和每个 3x3 子数独区域中出现过的数字。
  • rows[i] 用来记录第 i 行的数字,cols[j] 用来记录第 j 列的数字,boxes[k] 用来记录第 k 个 3x3 子数独的数字。
2. 遍历整个数独棋盘
ini 复制代码
for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
        const cell = board[i][j];
        if (cell === '.') continue; // 跳过空格
  • 外层循环遍历每一行 i,内层循环遍历每一列 j
  • 如果当前格子是空的(即 .),则跳过,直接进行下一个格子的检查。
3. 处理非空格的数字
ini 复制代码
const num = parseInt(cell, 10);
const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3); // 计算子数独索引
  • 将当前格子的字符 cell 转换为整数 num
  • boxIndex 计算出该数字所在的 3x3 子数独的索引。通过 Math.floor(i / 3)Math.floor(j / 3) 来确定它位于哪一个子数独(3x3 方阵)。
4. 检查当前数字是否在行、列或子数独中重复
ini 复制代码
if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {
    return false; // 如果在行、列或子数独中已经出现过该数字,返回 false
}
  • 如果当前数字 num 在当前行、列或子数独中已经出现过,立即返回 false,表示数独无效。
5. 标记当前数字在行、列和子数独中已出现
ini 复制代码
rows[i][num] = true;
cols[j][num] = true;
boxes[boxIndex][num] = true;
  • 如果当前数字没有在行、列和子数独中出现过,则将其标记为已出现,以便以后检查其他格子时避免重复。
6. 返回结果
kotlin 复制代码
return true; // 所有检查通过,数独有效
  • 如果遍历完所有格子都没有发现重复的数字,说明数独有效,返回 true

结语📖

总的来说这套题并不像是前端的面试题,考察的一种思维吧。

相关推荐
晓得迷路了2 分钟前
栗子前端技术周刊第 76 期 - ChatUI 3.0、Tailwind CSS v4.1、Next.js 15.3...
前端·javascript·react.js
植物系青年7 分钟前
前端性能优化全链路实践方案
前端·性能优化
植物系青年9 分钟前
前端 SSE 流式传输技术 🌊 对话大模型最佳拍档!
前端
Kagol11 分钟前
🎉TinyPro v1.2.0 正式发布,趁着 TinyPro 项目刚创建不久,快来参与贡献(蹭 PR)吧!
前端·vue.js·nestjs
洛小豆14 分钟前
想不到吧,这才是浏览器扩展中关闭窗口的正确姿势!
前端·javascript·chrome
Michael.Scofield22 分钟前
vue: router基础用法
前端·javascript·vue.js
excel25 分钟前
webpack 模块 第 五 节
前端
excel33 分钟前
webpack 模块 第 四 节
前端
好_快42 分钟前
Lodash源码阅读-take
前端·javascript·源码阅读
好_快43 分钟前
Lodash源码阅读-takeRight
前端·javascript·源码阅读