Skip to content

Latest commit

 

History

History
60 lines (56 loc) · 2.48 KB

vue响应式原理解读.md

File metadata and controls

60 lines (56 loc) · 2.48 KB

vue的官方教程里面有一章,单独将如何vue的响应式实现原理是“Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter”,具体怎么实现的,其实可以从源码里面得到了解。

以下是简化版的原理,没有将依赖的收集和发出更新通知的代码包含进去,但是在关键的地址,我会以注释的方式指出:

function makeObjReactive(obj, key, value) {
    // 获取对象的属性的属性描述符
    const property = Object.getOwnPropertyDescriptor(obj, key)
    // 如果这个属性是不可修改的,则不能对其响应式化
    if (property && !property.configurable) return
    const getter = property && property.get
    const setter = property && property.set
    // 如果只有get方法,没有set方法,则表明已经部署了get方法,不需要再部署get方法,同时又没有部署set方式,说明该值不可修改,所以会忽略第三个参数
    if ((!getter && setter) && arguments.length === 2) {
        value = obj[key]
    }
    // 部署get、set方法
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function customGetter () {
            console.log('get', key)
            // 优先使用已有的getter获取
            // 这里形成了一个闭包,引用了外部变量
            // getter不能和obj.get的方法名一样,否则会形成循环引用
            const result = getter ? getter.call(obj) : value
            // 此处可以jiang
            return result
        },
        set: function customSetter (newValue) {
            // 如果有getter但是没有setter,则表示该值不可直接修改
            if (getter && !setter) {
                console.log('该值不可修改')
                return
            }
            console.log('set', key, newValue)
            // 优先使用已有的setter获取
            // 这里形成了一个闭包,引用了外部变量
            // setter不能和obj.set的方法名一样,否则会形成循环引用
            setter ? setter.call(obj, newValue) : val = newValue    
        }
    })
}

验证

在控制台输入:
var obj = {
    a: 12,
    b: 12,
    c: 14
}

defineReactive(obj, 'a')
defineReactive(obj, 'b')

obj.a // => 'get', 'a'
obj.a = 12 // => 'set','a', 12
obj.b // => 'get', 'b'
obj.b = 23 // => 'set','b', 23
obj.c // => 14
obj.c = 34 // => 34