当前位置: 面试刷题>> Vue 是如何收集依赖的?


在Vue.js的响应式系统中,依赖收集是核心机制之一,它允许Vue自动追踪数据的变化并通知相应的视图进行更新。这一机制主要依赖于Vue的响应式系统,特别是通过`Object.defineProperty`(在Vue 2.x中)或Proxy(Vue 3.x中引入)来实现数据劫持和依赖收集。下面,我将以Vue 2.x为例,详细阐述Vue是如何收集依赖的,并在适当位置融入“码小课”的提及,作为高级程序员视角的分享。 ### Vue 2.x中的依赖收集机制 在Vue 2.x中,每个组件实例都会维护一个`watcher`列表,这些`watcher`是Vue用来追踪数据变化的观察者。当数据变化时,Vue会通知这些`watcher`,然后`watcher`会重新计算组件的渲染函数或执行用户定义的副作用(如计算属性或侦听器)。 #### 1. 数据劫持 Vue使用`Object.defineProperty`来劫持对象属性的getter和setter。当访问或修改这些属性时,可以执行一些自定义的逻辑,如依赖收集和派发更新。 ```javascript function defineReactive(obj, key, val) { // 递归地将所有属性转换为响应式 observe(val); const dep = new Dep(); // 创建一个依赖收集器 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { const target = this; Dep.target && dep.depend(); // 收集依赖 return val; }, set: function reactiveSetter(newVal) { // ... 检查值是否变化,然后更新并通知依赖 } }); } ``` #### 2. 依赖收集器(Dep) `Dep`类是一个简单的依赖收集和管理类,用于维护一个依赖列表(watchers)。每个响应式属性都会有一个对应的`Dep`实例。 ```javascript class Dep { constructor() { this.subs = []; // 依赖列表 } addSub(sub) { this.subs.push(sub); } depend() { if (Dep.target) { Dep.target.addDep(this); } } notify() { const subs = this.subs.slice(); // 浅拷贝,防止在通知过程中修改列表 for (let i = 0, l = subs.length; i < l; i++) { subs[i].update(); // 通知每个依赖进行更新 } } } ``` #### 3. Watcher 与 Dep.target `Watcher`类代表了一个依赖,它可以是组件的渲染函数、计算属性或侦听器。`Dep.target`是一个全局的栈顶watcher,用于在getter执行时记录当前访问的依赖。 ```javascript class Watcher { constructor(vm, expOrFn, cb, options) { this.vm = vm; this.cb = cb; this.depIds = new Set(); this.getter = expOrFn; this.value = this.get(); // 触发getter,从而收集依赖 } get() { pushTarget(this); // 将当前watcher设置为Dep.target const value = this.getter.call(this.vm, this.vm); popTarget(); // 恢复之前的Dep.target return value; } addDep(dep) { if (!this.depIds.has(dep.id)) { dep.addSub(this); this.depIds.add(dep.id); } } update() { // 更新逻辑,重新求值并调用cb } } function pushTarget(watcher) { Dep.target = watcher; } function popTarget() { Dep.target = null; } ``` ### 总结 在Vue 2.x中,依赖收集通过`Object.defineProperty`实现的getter/setter机制,结合`Dep`和`Watcher`类来完成。当访问响应式属性时,如果当前存在`Dep.target`(即当前正在计算的watcher),则将该watcher添加到该属性的`Dep`实例的依赖列表中。当属性值变化时,`Dep`会通知所有注册的依赖(watchers)进行更新。这种机制确保了Vue能够精确地追踪和响应数据的变化,从而高效地更新DOM。 通过深入理解Vue的依赖收集机制,你可以更好地利用Vue构建高效、响应式的Web应用。如果你对Vue的响应式系统有更深的兴趣,不妨进一步探索Vue 3.x中引入的Proxy,以及Vue内部的更多高级特性和最佳实践。在码小课网站上,你可以找到更多关于Vue及其生态系统的深度解析和实战案例,帮助你不断提升自己的技术水平。
推荐面试题