面试问题回答
小编大二找实习面试,跟面试官死缠烂打的一次,公司使用的是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. 组件封装实践
封装流程:
需求分析:明确组件功能边界
Props定义:定义可配置参数
export default { props: { type: { type: String, default: 'primary' } } }
插槽处理:使用
<slot>
实现内容分发<button class="my-button"> <slot>默认按钮</slot> </button>
事件通信:通过
$emit
触发事件<button @click="$emit('click')">
v-model支持:实现双向绑定
model: { prop: 'value', event: 'change' }
6. Vue2的痛点
常见痛点:
- 响应式限制:
- 无法检测数组索引修改:
arr[0] = newVal
- 无法检测对象属性添加/删除
- 无法检测数组索引修改:
- 代码组织:
- Mixins导致命名冲突和来源不清晰
// mixinA.js 和 mixinB.js 可能都有同名方法
- TS支持弱:选项式API对TypeScript类型推断不友好
- 性能问题:深度嵌套对象递归劫持性能消耗大
- 逻辑复用:相同逻辑需要在不同组件重复实现
- 大型项目:随着项目增大,组件间通信复杂度上升
解决方案趋势:这些痛点促使了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
将它们转为响应式。但后续动态添加或删除属性时:
- 新属性未被
Object.defineProperty
劫持。 - 删除属性不会触发
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
的核心逻辑:
- 检查目标是否为响应式对象:只有Vue管理的对象才能被处理。
- 添加属性并转为响应式:对新属性调用
defineReactive
方法(内部使用Object.defineProperty
)。 - 手动触发依赖更新:通知所有关联的
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.set
或Vue.delete
显式处理动态属性,否则会破坏响应式。这一机制是Vue2响应式系统的核心设计局限,也是开发者常见的“踩坑点”。