九方前端面试

发布于:2025-04-21 ⋅ 阅读:(14) ⋅ 点赞:(0)

面试问题回答

小编大二找实习面试,跟面试官死缠烂打的一次,公司使用的是vue2和vue3较多,所以问的比较多的是vue2和es6,以下是总结的面试官喜欢问的几个点。

1. ES6新特性有哪些?

核心特性

  • let/const:块级作用域变量声明

  • 箭头函数:简化函数写法,自动绑定外层this

    const add = (a, b) => a + b;
    
  • 模板字符串:支持多行字符串和变量嵌入

    const name = 'Alice';
    console.log(`Hello, ${name}!`);
    
  • 解构赋值:从数组/对象中提取值

    const [a, b] = [1, 2];
    const { name, age } = user;
    
  • 默认参数:函数参数默认值

    function greet(name = 'Guest') { /* ... */ }
    
  • 类(Class):语法糖面向对象编程

    class Person {
      constructor(name) { this.name = name; }
    }
    
  • 模块化import/export模块系统

  • Promise:异步编程解决方案

  • Symbol:唯一不可变数据类型

  • Set/Map:新数据结构


2. ES6数组新增了什么?

新增方法

  • 扩展运算符...展开数组

    const arr = [...[1,2], 3]; // [1,2,3]
    
  • Array.from():类数组转数组

    Array.from(document.querySelectorAll('div'));
    
  • Array.of():创建数组

    Array.of(1,2,3); // [1,2,3]
    
  • find()/findIndex():查找元素

    [1,2,3].find(x => x > 1); // 2
    
  • includes():判断包含元素

    [1,2,3].includes(2); // true
    
  • fill():填充数组

    new Array(3).fill(0); // [0,0,0]
    
  • entries()/keys()/values():遍历方法


3. Vue2的响应式原理是什么?

核心机制

  • Object.defineProperty:劫持对象属性

    function defineReactive(obj, key) {
      let value = obj[key];
      Object.defineProperty(obj, key, {
        get() {
          console.log('收集依赖');
          return value;
        },
        set(newVal) {
          console.log('触发更新');
          value = newVal;
        }
      });
    }
    
  • 依赖收集:通过Dep类和Watcher实现

  • 数组处理:重写数组方法(push/pop等)

    const arrayProto = Array.prototype;
    const arrayMethods = Object.create(arrayProto);
    ['push', 'pop'].forEach(method => {
      const original = arrayProto[method];
      arrayMethods[method] = function(...args) {
        const result = original.apply(this, args);
        dep.notify(); // 手动触发更新
        return result;
      };
    });
    
  • 局限性:无法检测到对象属性新增/删除(需用Vue.set


4. Axios的二次封装

典型封装方案

// src/utils/request.js
import axios from 'axios';

const service = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000
});

// 请求拦截器
service.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
}, error => {
  return Promise.reject(error);
});

// 响应拦截器
service.interceptors.response.use(response => {
  return response.data;
}, error => {
  if (error.response.status === 401) {
    // 处理未授权
  }
  return Promise.reject(error);
});

// 封装GET/POST
export function get(url, params) {
  return service.get(url, { params });
}

export function post(url, data) {
  return service.post(url, data);
}

5. 组件封装实践

封装流程

  1. 需求分析:明确组件功能边界

  2. Props定义:定义可配置参数

    export default {
      props: {
        type: {
          type: String,
          default: 'primary'
        }
      }
    }
    
  3. 插槽处理:使用<slot>实现内容分发

    <button class="my-button">
      <slot>默认按钮</slot>
    </button>
    
  4. 事件通信:通过$emit触发事件

    <button @click="$emit('click')">
    
  5. v-model支持:实现双向绑定

    model: {
      prop: 'value',
      event: 'change'
    }
    

6. Vue2的痛点

常见痛点

  1. 响应式限制
    • 无法检测数组索引修改:arr[0] = newVal
    • 无法检测对象属性添加/删除
  2. 代码组织
    • Mixins导致命名冲突和来源不清晰
    // mixinA.js 和 mixinB.js 可能都有同名方法
    
  3. TS支持弱:选项式API对TypeScript类型推断不友好
  4. 性能问题:深度嵌套对象递归劫持性能消耗大
  5. 逻辑复用:相同逻辑需要在不同组件重复实现
  6. 大型项目:随着项目增大,组件间通信复杂度上升

解决方案趋势:这些痛点促使了Vue3的Composition API诞生


7-补充:Vue2响应式对对象属性新增/删除的局限性(当时说不出来这个set)

问题背景

Vue2使用Object.defineProperty实现响应式,但其核心限制是只能劫持对象已存在的属性。这意味着:

  • 新增属性:直接通过obj.newKey = value添加的属性无法触发视图更新。
  • 删除属性:通过delete obj.key删除属性也无法触发更新。

示例场景

// Vue实例中定义的data
data() {
  return {
    user: { name: "Alice" }
  };
}

// 直接新增属性(不会触发响应式更新)
this.user.age = 25; // ❌ 视图不会更新

// 直接删除属性(不会触发响应式更新)
delete this.user.name; // ❌ 视图不会更新

问题根源

Vue2在初始化时会递归遍历data中的所有属性,并用Object.defineProperty将它们转为响应式。但后续动态添加或删除属性时:

  1. 新属性未被Object.defineProperty劫持。
  2. 删除属性不会触发setter逻辑。

解决方案:Vue.set / this.$set

通过Vue.set(或实例方法this.$set)强制让新属性具备响应性。

语法
Vue.set(target, propertyName/index, value);
// 或组件内使用:
this.$set(target, propertyName/index, value);
对象属性示例
// 正确添加响应式属性
this.$set(this.user, "age", 25); // ✅ 视图更新

// 正确删除属性(需用Vue.delete)
Vue.delete(this.user, "name"); // ✅ 视图更新
数组场景示例

Vue2对数组的以下操作无法触发更新:

// 直接通过索引修改数组
this.items[0] = "newValue"; // ❌ 视图不会更新

// 正确方式
this.$set(this.items, 0, "newValue"); // ✅ 视图更新

底层原理

Vue.set的核心逻辑:

  1. 检查目标是否为响应式对象:只有Vue管理的对象才能被处理。
  2. 添加属性并转为响应式:对新属性调用defineReactive方法(内部使用Object.defineProperty)。
  3. 手动触发依赖更新:通知所有关联的Watcher重新渲染。

Vue3的改进

Vue3使用Proxy替代Object.defineProperty,解决了这一问题:

  • Proxy可以拦截对象的所有操作(包括属性增删)。
  • 无需手动调用set/delete,动态属性天然支持响应式。

总结

操作类型 Vue2的限制 Vue2的解决方案 Vue3的支持
对象新增属性 ❌ 无法检测 this.$set(obj, key, value) ✅ 天然支持
对象删除属性 ❌ 无法检测 Vue.delete(obj, key) ✅ 天然支持
数组索引修改 ❌ 无法检测 this.$set(arr, index, val) ✅ 天然支持

关键点:在Vue2中,必须通过Vue.setVue.delete显式处理动态属性,否则会破坏响应式。这一机制是Vue2响应式系统的核心设计局限,也是开发者常见的“踩坑点”。


网站公告

今日签到

点亮在社区的每一天
去签到