深入vue2.0源码系列:依赖追踪与计算属性的实现
创始人
2025-05-30 03:11:00
0

前言

在 Vue.js 中,数据与视图之间的绑定是通过依赖追踪和计算属性来实现的。本文将深入学习 Vue.js 2.0 源码中依赖追踪和计算属性的实现原理。

依赖追踪

在 Vue.js 中,依赖追踪是实现响应式的核心。当一个响应式对象被访问时,Vue.js 会自动追踪这个对象的依赖关系,并将这些依赖关系建立成一个依赖图。当这个响应式对象的值发生改变时,Vue.js 会遍历这个依赖图,通知所有依赖于这个对象的地方更新视图。

Vue.js 中的依赖追踪是通过 Dep 类来实现的。每个响应式对象都对应一个 Dep 对象,它维护了这个响应式对象的所有依赖关系。

具体来说,当一个响应式对象被访问时,会触发它的 getter 函数。在 getter 函数中,会调用 Dep.targetaddDep 方法,将当前正在计算的计算属性或者渲染 Watcher 添加到这个响应式对象的 Dep 对象的依赖列表中。Dep.target 就是一个全局唯一的 Watcher,它代表当前正在计算的计算属性或者正在渲染的组件的 Watcher。这样就完成了依赖关系的建立。

下面是 Dep 类的简化实现:

class Dep {constructor() {this.subs = []; // 存储依赖于该响应式对象的所有 Watcher}depend() {if (Dep.target) {Dep.target.addDep(this); // 将当前正在计算的 Watcher 添加到依赖列表中}}notify() {for (let i = 0; i < this.subs.length; i++) {this.subs[i].update(); // 通知依赖于该响应式对象的所有 Watcher 更新视图}}addSub(sub) {this.subs.push(sub);}
}Dep.target = null;

上述代码中的 depend 方法用于在 getter 函数中添加依赖关系,notify 方法用于在响应式对象发生改变时通知所有依赖该对象的 Watcher 更新视图。而 addSub 方法则用于添加依赖于该响应式对象的 Watcher。

计算属性

计算属性是 Vue.js 中的一个重要特性,它允许开发者声明式地计算出一个值,并在模板中使用计算属性是通过 Watcher 类来实现的。每个计算属性都对应一个 Watcher 对象,它会自动追踪计算属性的依赖关系,并在依赖的数据发生改变时重新计算值并更新视图。

具体来说,当一个计算属性被访问时,会触发它的 getter 函数。在 getter 函数中,会调用 Dep.targetpushTarget 方法,将当前计算属性的 Watcher 设置为全局唯一的 Dep.target。这样,在计算属性的计算过程中,如果访问了响应式数据,就会触发这些响应式数据的 getter 函数,并将当前计算属性的 Watcher 添加到它们的 Dep 对象的依赖列表中。

当计算属性的依赖数据发生改变时,会触发这些数据对应的 Dep 对象的 notify 方法,通知所有依赖于这些数据的 Watcher 更新视图。而这些 Watcher 中,因为计算属性的 Watcher 也被添加到了它们的依赖列表中,所以也会被通知到。这样,计算属性的值就会重新计算,并更新视图。

下面是 Watcher 类的简化实现:

class Watcher {constructor(vm, expOrFn, cb) {this.vm = vm;this.getter = expOrFn;this.cb = cb;this.deps = [];this.depIds = new Set();this.value = this.get();}get() {Dep.target = this; // 将当前 Watcher 设置为全局唯一的 Dep.targetconst value = this.getter.call(this.vm); // 触发计算属性的 getter 函数,建立依赖关系Dep.target = null; // 恢复全局唯一的 Dep.targetreturn value;}update() {const oldValue = this.value;this.value = this.get(); // 重新计算计算属性的值this.cb.call(this.vm, this.value, oldValue); // 更新视图}addDep(dep) {const id = dep.id;if (!this.depIds.has(id)) {this.deps.push(dep); // 将依赖于该响应式对象的 Watcher 添加到该响应式对象的依赖列表中this.depIds.add(id);dep.addSub(this); // 将该 Watcher 添加到该响应式对象的依赖列表中}}
}

上述代码中的 addDep 方法用于在计算属性的 getter 函数中添加依赖关系,并将该计算属性的 Watcher 添加到依赖的响应式对象的 Dep 对象的依赖列表中。
了解这些原理可以帮助我们更好地理解 Vue.js 的响应式系统,并能更深入地理解计算属性和依赖追踪的机制。同时,我们也可以通过修改 Watcher 的实现方式,实现自定义的响应式行为。

下面是一个简单的例子,展示如何使用 Watcher 自定义响应式行为:

class CustomWatcher extends Watcher {constructor(vm, expOrFn, cb) {super(vm, expOrFn, cb);this.update(); // 在创建 CustomWatcher 时,先手动更新一次视图}update() {const oldValue = this.value;this.value = this.get(); // 调用父类的 get 方法计算新值this.cb.call(this.vm, this.value, oldValue); // 触发回调函数}
}

上述代码中的 CustomWatcher 类继承自 Watcher 类,并重写了 update 方法,将原来的更新视图的逻辑替换成了触发回调函数的逻辑。这样,在创建 CustomWatcher 时,只需要传入计算新值的函数和回调函数,就可以实现自定义的响应式行为。

总结

总结来说,依赖追踪和计算属性是 Vue.js 响应式系统的核心机制。通过依赖追踪,Vue.js 能够自动建立响应式数据之间的依赖关系,并在数据发生改变时自动更新视图。而计算属性则能够让我们将复杂的数据计算逻辑封装起来,以便更好地组织和复用代码。理解这些机制可以帮助我们更好地使用 Vue.js,同时也能够启发我们设计自己的响应式系统。

后续会继续更新vue2.0其他源码系列,包括目前在学习vue3.0源码也会后续更新出来,喜欢的点点关注。

相关内容

热门资讯

银行、消金公司助贷余额增速不得... 近日,中国证券报记者从多位业内人士处独家获悉,5月以来,多地金融监管部门对部分中小银行、消金公司下达...
朱鸿接任陈航,担任钉钉科技有限... 消费日报-今朝新闻讯 天眼查显示,6月23日,钉钉科技有限公司发生工商变更,陈航卸任法定代表人、董事...
3日累跌超20%,德创环保:公... 6月25日, 德创环保(603177.SH)公告,公司股票于2026年6月23日、6月24日和6月2...
北京发布2026年第七轮拟供商... 央广网北京6月25日消息(记者门庭婷)6月25日,北京市规划和自然资源委员会网站发布了2026年第七...
开放麦 | 启明创投胡奇:从A... “2026年,创投圈的浪潮再次翻涌:AI从技术概念走进产业深水区,硬科技创业从“小众赛道” 变成“主...
腾讯孙忠怀:在行业转身处 6月24日,2026腾讯视频年度发布在上海举行。腾讯公司副总裁、腾讯在线视频董事长孙忠怀以《在行业转...
加息,突变!美联储,重磅传来!... 美联储政策路径突生变数。 美国商务部经济分析局最新公布的数据显示,5月个人消费支出(PCE)物价指数...
6月合肥上门收金必看!5步避坑... 2026年6月,合肥黄金市场持续高位运行,不少市民翻出家里闲置的旧金饰、投资金条想变现,上门回收因为...
潮汕女富豪挂帅后加码液冷!祥鑫... 潮汕女强人,带着百亿公司加码液冷散热。 6月24日晚间,祥鑫科技(002965.SZ)公告称,公司董...
马斯克向太空要电,GobiX ... 一场关于「去哪里找电」的全球竞赛,正在朝两个方向展开。 作者|周永亮 编辑| 郑玄 「太空光伏是不是...
原料药行业陷入周期低谷 有药企... 每经记者|许立波 每经编辑|魏文艺 “过完年到现在,我们整个团队每个月都在出差,跑遍了亚非拉、欧美市...
家门口筛查白内障!永顺泽家镇暖... 大众卫生报·新湖南客户端6月25日讯(通讯员 彭雪姣)为切实解决辖区老年性白内障患者异地就医奔波、就...
终于等到!油价马上再大跌,这个... 点击添加图片描述(最多60个字) 编辑 各位车主朋友,好消息接二连三! 继6月18日油价大幅下调...
丈量出海新路 世界酒庄影响力指... 长期以来,全球酒庄评价体系由西方机构主导,且大多局限于单一酒种、单一评价维度,这一局面正逐渐被打破。...
峰瑞资本创始合伙人李丰:从资本... “2026年,创投圈的浪潮再次翻涌:AI从技术概念走进产业深水区,硬科技创业从“小众赛道” 变成“主...
原创 A... 迈向成熟,还有茁壮成长的机会。 作者 | 方璐 编辑丨于婞 来源 | 野马财经 2026年6月21日...
为企业解锁出海新通道!亚太中小... 6月24日下午,作为2026年APEC中小企业工商论坛的重要组成部分,亚太中小企业国际化合作发展论坛...
君赛生物港股IPO,增聘兴证国... 跟丰宜科技一样,正冲刺港股IPO的上海君赛生物股份有限公司(简称“君赛生物”)增聘一位整体协调人。 ...
圣邦股份明日上市:暗盘涨24%... 雷递网 雷建平 6月25日 圣邦微电子(北京)股份有限公司(简称:“圣邦股份”,股票代码:“0366...
科技“吃肉”,券商跟着“喝汤”... 当科技持续成为市场核心主线,押中硬科技项目的券商也成为被追逐的焦点。 6月24日,半导体零部件概念股...