Vue2与Vue3的响应式原理

大家好,今天给大家分享一下Vue2和Vue3的响应式原理;说到响应式无非就是监听属性的获取,修改及删除...,了解逻辑之后再去实现底层代码岂不是快了许多=_=

Vue2响应式

原理:利用defineReactive方法,通过defineProperty对属性进行劫持,数组则是通过重写其方法来进行劫持,每个属性值都拥有自己的dep属性,用来存取所依赖的watch,当数据发生改变时,触发相应的watch去更新数据

 代码实现:

const { arrayMethods } = require('./array')

class Observer {
    constructor(value) {
        Object.defineProperty(value, '__ob__', {
            value: this,
            enumerable: false,
            writable: true,
            configurable: true
        })
        if(Array.isArray(value)) {
            value.__proto__ = arrayMethods
            this.observeArray(value)
        } else {
            this.walk(value)
        }
    }

    walk(data) {
        let keys = Object.keys(data)
        for(let i = 0; i < keys.length; i++) {
            const key = keys[i]
            const value = data[key]
            defineReactive(data, key, value)
        }
    }

    observeArray(items) {
        for(let i = 0; i < items.length; i++) {
            observe(items[i])
        }
    }
}

function defineReactive(data, key, value) {
    const childOb = observe(value)

    const dep = new Dep()

    Object.defineProperty(data, key, {
        get() {
            console.log('获取值')
            if (Dep.target) {
                dep.depend()

                if (childOb) {
                    childOb.dep.depend()

                    if (Array.isArray(value)) {
                        dependArray(value)
                    }
                }
            }
            return value
        },
        set(newVal) {
            if (newVal === value) return
            observe(newVal)
            value = newVal
            dep.notify()
        }
    })
}

function observe(value) {
    if (Object.prototype.toString.call(value) === '[object Object]' || Array.isArray(value)) {
        return new Observer(value)
    }
}

function dependArray(value) {
    for(let e, i = 0, l = value.length; i < l; i++) {
        e = value[i]

        e && e.__ob__ && e.__ob__.dep.depend()

        if (Array.isArray(e)) {
            dependArray(e)
        }
    }
}

// array.js
const arrayProto = Array.prototype

const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'reverse',
    'sort'
]

methodsToPatch.forEach(method => {
    arrayMethods[method] = function (...args) {
        const result = arrayProto[method].apply(this, args)

        const ob = this.__ob__

        var inserted

        switch (method) {
            case 'push':
            case 'unshift':
                inserted = args
                break;
            case 'splice':
                inserted = args.slice(2)
            default:
                break;
        }

        if (inserted) ob.observeArray(inserted)

        ob.dep.notify()

        return result
    }
})

但是呢,Vue2的响应式还存在一些缺陷:1.对象新增属性,删除属性界面不会更新 2.通过数组下标修改数组内容界面不会更新

原因:1.Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的

2.通过数组下标修改数组不会触发响应,因为尤雨溪用了重写数组的方法来实现数据的响应绑定,当vue遇到push pop shift unshift splice sort reverse 的时候数组才会改变

 解决方案:1.对象:对象新增属性无法更新视图,通过Vue.$set(obj,key,value),组件中通过this.$set(obj,key,value)

2.数组:通过数组下标修改数组不会触发视图更新,可以通过Vue.$set(obj,key,value),也可以通过push pop shift unshift splice sort reverse方法来实现响应

 Vue3的响应式弥补了Vue2响应式的缺陷,并且还带来了许多优化,下面让我们来了解一下Vue3响应式的基本雏形

Vue3响应式雏形

原理:利用了Proxy和Reflect来代替Vue2的Object.defineProperty()方法来重写响应式

 这只是基本的代码:

        let person = {
            name: '张三',
            age: 18
        }
        const p = new Proxy(person, {
            get(target, propName) {
                console.log(`我的${propName}值被获取了`);
                return Reflect.get(target, propName)
            },
            set(target, propName, value) {
                console.log(`我的${propName}值被修改了`);
                Reflect.set(target, propName, value)
            },
            deleteProperty(target, propName) {
                console.log(`我的${propName}值被删除了`);
                Reflect.deleteProperty(target, propName)
            }
        })

target指的是整个person,propName指的是person中的某个属性,value指的是新值。

运行结果:

 Vue3的响应式相较于Vue2的优势:

  • 用 Proxy 和 Reflect 来代替 vue2 中的 Object.definepeoperty()方法来重写响应式
  • vue3 中可以监听动态新增的属性
  • vue3 中可以监听删除的属性
  • vue3 中可以监听数组的索引和 length 属性
  • 代码的执行效果更快
  • Proxy 可以直接监听对象而非属性
  • Proxy 可以直接监听数组的变化
  • Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的
  • Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改
  • Proxy 不需要初始化的时候遍历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性

 以上就是对Vue2和Vue3响应式的介绍,希望能够帮到大家!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue2和Vue3的响应式原理有以下区别: 1. 实现方式不同:Vue2使用Object.defineProperty()来对对象的属性进行拦截,Vue3则使用代理来拦截对象中任意属性的变化。 2. 默认进行懒观察:在Vue2中,不管数据有多大,都会在一开始就为其创建观察者,这可能会在页面加载时造成性能压力。而Vue3只会对「被用于渲染初始可见部分的数据」创建观察者,并且Vue3的观察者更高效。 3. 对新增属性的处理不同:在Vue2中,使用Vue.set()来给对象新增一个属性时,这个对象的所有watcher都会重新运行。而在Vue3中,只有依赖该属性的watcher才会重新运行。 4. Vue3的模板支持多个子元素:Vue3的模板可以支持多个连续的子元素,而Vue2的模板需要在外层包裹一个根元素。 5. 生命周期的变化:在Vue3中,使用setup()函数来替换Vue2中的beforeCreate和created生命周期钩子函数。 综上所述,Vue2和Vue3的响应式原理在实现方式、观察对象的创建时机、新增属性的处理、模板支持和生命周期等方面存在一些区别。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [三、【Vue3】——Vue2与Vue3响应式原理区别](https://blog.csdn.net/yifei1234567/article/details/123841084)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [vue2和vue3的响应式数据原理和区别](https://blog.csdn.net/hkduan/article/details/113916315)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是个程序员吧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值