Vue2中响应式系统的底层细节。

Vue2的响应式系统依赖于Object.defineProperty实现数据劫持,通过数据代理将data对象的属性操作映射到vm实例上。当读取或修改属性时,getter和setter确保了数据的更新并触发视图的更新。数据代理过程中,使用MVVM模式和Observer、Compile等组件,确保了数据变化的追踪。Vue2中通过Vue.set和Vue.delete处理新增或删除属性的响应式问题,而在Vue3中对此进行了改进。

Vue2中响应式系统的底层细节。

vue2是利用Object.defineProperty方法劫持对象或对象的属性的访问器,在属性值发生变化时获取属性值变化, 从而进行后续操作。这个方法有三个参数,第一个参数obj表示要定义的对象,第二个参数prop表示对象的某个属性值,用字符串表示,第三个参数descriptor是用来控制prop的,重点介绍一下第三个参数,它传入一个对象,对象包括以下的属性值:

value:给prop属性赋值

enumerable:控制属性是否可被遍历,默认是false

writeable:控制属性是否可以被修改,默认是false

configurable:控制属性是否可以被删除,默认是false

get():当程序读取prop属性的时候,get函数(getter)就会被调用

set():当程序修改prop属性的时候,set函数(setter)就会被调用

数据代理

数据代理就是通过一个对象去代理另外一个对象中属性的操作(读/写),下面通过defineProperty方法实现一下数据代理:

function MVVM(options) {

    // 将选项对象保存到vm

    this.$options = options;

    // 将data对象保存到vm和data变量中

    var data = this._data = this.$options.data;

    //将vm保存在me变量中

    var me = this;

    // 遍历data中所有属性

    Object.keys(data).forEach(function (key) { // 属性名: name

        // 对指定属性实现代理

        me._proxy(key);

    });

    // 对data进行监视

    observe(data, this);

    // 创建一个用来编译模板的compile对象

    this.$compile = new Compile(options.el || document.body, this)

}

MVVM.prototype = {

    $watch: function (key, cb, options) {

        new Watcher(this, key, cb);

    },

    // 对指定属性实现代理

    _proxy: function (key) {

        // 保存vm

        var me = this;

        // 给vm添加指定属性名的属性(使用属性描述)

        Object.defineProperty(me, key, {

            configurable: false, // 不能再重新定义

            enumerable: true, // 可以枚举

            // 当通过vm.name读取属性值时自动调用

            get: function proxyGetter() {

                // 读取data中对应属性值返回(实现代理读操作)

                return me._data[key];

            },

            // 当通过vm.name = 'xxx'时自动调用

            set: function proxySetter(newVal) {

                // 将最新的值保存到data中对应的属性上(实现代理写操作)

                me._data[key] = newVal;

            }

        });

    }

};

基本实现流程

(1)通过 Object.defineProperty()给 vm 添加与 data 对象的属性对应的属性描述符

(2)所有添加的属性都包含 getter/setter

(3) getter/setter 内部去操作 data 中对应的属性数据

3.Vue中的数据代理

是通过vm实例对象来代理data对象中属性的读取和修改,这样的好处就是更加方便的操作data中的数据,他的基本原理是通过Object.defindProprerty

方法把data所有属性都添加到vm实例对象上,为添加到vm实例对象的每一个属性都指定一个getter/setter,在getter和setter内部去读写data中对应的属性。

每当要修改的Vue中data对应的属性值,就会触发vm中对应属性的set方法,同时去更新View层视图的值,这就是Vue中的响应式原理,但是defindProperty()方法中没有定义属性值添加/删除的方法,当要往data中添加或者删除的时候,defindProerty()无法完成响应式,这个问题在Vue3中得到了改善。Vue2也提供了完整的解决方案,可通过Vue.set()/this.$set()添加属性,Vue.delete()/this.$delete()删除属性

总结一下,今天讲了vue2中数据的响应式是通过数据代理完成的,而数据代理的主要核心就是Object.defindProperty()这个方法

### Vue 2 响应式机制与实现原理 Vue 2响应式机制主要依赖于 JavaScript 的 `Object.defineProperty` 方法来劫持数据的访问和修改。通过这一机制,Vue 能够在数据发生变化时自动更新视图,并且能够在视图变化时更新数据,从而实现双向绑定。 #### 数据劫持与依赖追踪 在 Vue 2 中,当一个 Vue 实例被创建时,它会递归地遍历其 `data` 属性,并使用 `Object.defineProperty` 来将这些属性转换为 getter 和 setter。这样做的目的是为了能够监听到数据的变化[^1]。每当一个属性被访问时,getter 就会被触发,此时可以进行依赖收集;而当属性值被改变时,setter 会被调用,这就可以通知所有依赖项进行更新。 ```javascript // 示例:使用 Object.defineProperty 劫持数据 function defineReactive(obj, key, val) { const dep = []; // 存储订阅者列表 Object.defineProperty(obj, key, { enumerable: true, configurable: false, get: function reactiveGetter() { if (Dep.target) { dep.push(Dep.target); // 收集依赖 } return val; }, set: function reactiveSetter(newVal) { if (newVal === val) return; val = newVal; dep.forEach(watcher => watcher.update()); // 通知依赖更新 } }); } ``` #### 视图编译与指令解析 除了数据劫持之外,Vue 还需要处理模板中的指令,这个过程称为编译(Compile)。在这个阶段,Vue 会解析模板中的指令并生成渲染函数。每个指令都会对应一个 `Watcher` 对象,它是连接数据和视图的关键[^2]。 #### Watcher 桥梁作用 `Watcher` 是 Observer 和 Compile 之间的桥梁。当数据发生改变时,Observer 会通知相应的 Watcher,然后由 Watcher 去更新 DOM。同样地,如果用户通过表单等交互改变了视图,这种变化也会通过 Watcher 反向更新到数据模型中。 ```javascript // 简化的 Watcher 类示例 class Watcher { constructor(vm, expOrFn, cb) { this.vm = vm; this.getter = parsePath(expOrFn); // 解析路径得到获取值的方法 this.cb = cb; this.value = this.get(); // 初始化时取一次值以建立依赖关系 } get() { Dep.target = this; // 设置当前 Wacher 为全局目标 const value = this.getter.call(this.vm, this.vm); Dep.target = null; // 清除全局目标 return value; } update() { const oldValue = this.value; this.value = this.get(); this.cb.call(this.vm, this.value, oldValue); // 执行回调,通常用来更新视图 } } ``` #### 总结 综上所述,Vue 2响应式系统是通过结合 `Object.defineProperty` 的数据劫持、依赖收集以及 Watcher 的更新策略来实现的。这样的设计使得开发者能够专注于业务逻辑而不必过多关注底层的数据绑定细节,同时也保证了高效的变更检测和最小化的视图重绘次数。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重塑这战争

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值