1、Vue的响应式原理是什么?Vue2和Vue3的实现机制有何区别?
答:Vue响应式其核心目标:当数据变化时,自动触发依赖该数据的视图更新。实现方式主要有两步:依赖收集 和 数据变化派发更新
Vue2 的实现机制
- 技术核心:
Object.defineProperty劫持数据的getter/setter - 流程:
- 初始化数据时,遍历对象的每个属性,用
Object.defineProperty定义getter/setter。 getter中收集依赖(Dep存储Watcher)setter中通知依赖更新(Dep.notify)
- 初始化数据时,遍历对象的每个属性,用
- 依赖管理:
- Dep:每个属性对应一个依赖管理器
- Watcher:订阅者(组件渲染函数、计算属性等)
- 缺点:
- 无法监听属性新增/删除
- 无法监听数组索引修改和
length变化 - 初始化时需要递归遍历所有属性,性能差
Vue3 的实现机制
- 技术核心:
Proxy+Reflect - 流程:
- 使用
reactive()时返回一个Proxy对象 get时调用track收集依赖(按需追踪)set时调用trigger触发依赖更新
- 使用
- 优化:
- 按需追踪:只有访问过的属性才收集依赖
- 懒代理:深层对象只有在访问时才会递归代理
- 批量更新:依赖更新合并到微任务队列中执行,减少渲染次数
- 优点:
- 支持新增 / 删除属性、数组索引、length 变化
- 性能更好,内存占用更少
2、Vue 生命周期中 created 和 mounted 区别?分别适用于什么?
created:实例创建完成(data、methods 已初始化),但 DOM 还没生成;- 适合数据初始化、调用
API请求数据 - 不能操作
DOM(因为还没生成) - 更早执行,可以减少首屏延迟
- 适合数据初始化、调用
mounted:模板渲染完成,真实DOM挂载到页面- 适合需要访问
真实DOM的操作(如操作canvas、调用第三方DOM插件) - 数据和
DOM都可用 - 在首次渲染之后执行
- 适合需要访问
3、什么是作用域链?与原型链的区别是什么?
答:**作用域链(Scope Chain)**是 JS 执行环境(函数、块等)查找变量的一种机制。当访问一个变量时,JS引擎会沿着作用域链向上查找,直到找到为止,找不到则报ReferenceError。
- 每个执行上下文(函数、全局等)都有一个 变量环境(Variable Environment)。
- 当在函数内部访问变量时:
- 先查找当前上下文的变量环境。
- 如果找不到,则查找父级作用域的变量环境。
- 一直向上直到全局作用域。
- 所有这些变量环境按 链式结构连接起来,就形成了作用域链。
原型链:是对象查找属性的方法。当访问对象的某个属性时,如果对象本身没有,则会沿着原型链查找,直到找到或到达null。
- 每个对象都有一个隐藏属性
[[Prototype]](通常用__proto__表示)。 - 查找属性时:
- 先查找对象自身的属性。
- 如果没有,则查找
[[Prototype]]指向的对象。 - 一直向上查找直到
null。
作用域链:解决 “变量在哪里找” 的问题; 原型链:解决 “对象属性在哪里找” 的问题 两者都是链式结构,但作用域链是静态的(函数定义时决定父作用域),原型链是动态的(对象创建时决定原型)。
4、如何实现函数防抖与节流?应用在哪些场景?
答:函数防抖(Debounce):在事件被频繁触发时,只执行最后一次。事件触发后,延迟一段时间执行函数,如果在延迟时间内又触发了事件,就重新计时。
应用场景:
- 搜索输入框:用户停止输入一段时间后再发请求,避免每个字都请求一次。
- 窗口
resize事件:停止调整窗口后再执行逻辑。 - 表单验证:用户停止输入时再校验。
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
函数节流(Throttle):在事件被频繁触发时,保证一定时间间隔内只执行一次。通过时间戳或定时器,让函数在一个固定间隔内执行。
应用场景:
- 滚动事件(scroll):页面滚动时,每隔一段时间触发一次,比如懒加载。
- 按钮点击:防止用户短时间内多次点击提交按钮。
- 鼠标移动事件(mousemove):限制触发频率,提升性能。
function Throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
5、说说Event Loop的运行机制?宏任务与微任务的区别是什么?
答:JavaScript是单线程的,所有任务在同一个主线程上排队执行。为了协调同步任务和异步任务的执行,浏览器和Node.js实现了 事件循环机制(Event Loop)。运行机制大致是:
- 同步任务 → 直接在主线程执行,进入 执行栈(Call Stack)。
- 异步任务 → 比如
定时器、Promise、DOM事件,会先交给浏览器或Node的API处理。 - 执行栈清空后,事件循环从**任务队列(Task Queue)**中取任务放到执行栈中执行。
宏任务 MacroTask:每次从事件队列中取出来的任务就是一个宏任务。常见的宏任务:setTimeout、setInterval、setImmediate(Node.js)、I/O 操作、UI 渲染
微任务 MicroTask:在当前宏任务执行完毕后、下一个宏任务开始前,会清空所有微任务队列。常见的微任务:Promise.then / catch / finally、queueMicrotask、MutationObserver
执行顺序
- 执行全局脚本(这也是一个宏任务)。
- 执行过程中如果遇到微任务,放到微任务队列。
- 当前宏任务执行完毕 → 立即清空所有微任务队列。
- 再从宏任务队列中取出下一个宏任务执行。
- 如此循环。