乐趣区

关于javascript:手写数据响应式

响应式定义

响应式就是数据模型发生变化能够收回相应响应, 比方调用一个函数

性能实现

vue 广泛走的是数据劫持形式, 不同在于 vue2 应用 object.defineproperty,vue3 应用的是 proxy. 也就是一次一个属性劫持, 还是一次劫持一个对象.
proxy/reflect 是 es2015 标准中退出的, proxy 能够更好地拦挡对象, 而 reflect 能够更优雅的操作对象

proxy/reflect 的劣势

  • 针对整个对象定制, 而不是对象的某个属性, 所以不须要进行 key 值遍历
  • 反对数组, 省去了重载数组办法的 hack 过程
  • proxy 的第二个参数由 13 种拦挡办法,
  • 能够通过递归不便的进行对象嵌套
应用 defineproperty 进行对象劫持
let effective
function effect(fun) {effective = fun}

function reactive(data) {if (typeof data !== 'object' || data === null) {return data}


    Object.keys(data).forEach(function (key) {let value = data[key]
        // 递归调用~~~~
        reactive(value)
        Object.defineProperty(data, key, {
            emumerable: false,
            configurable: true,
            get: () => {return value},
            set: newVal => {if (newVal !== value) {effective()
                    value = newVal
                }
            }
        })

    })
    return data
}
vue2 数组函数劫持
function hashArray(data) {
    const oldArrayPrototype = Array.prototype
    const proto = Object.create(oldArrayPrototype);

    ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {

        // 函数劫持
        proto[method] = function () {effective()
            console.log('批改数组的值')
            oldArrayPrototype[method].call(this, ...arguments)
        }
    })
    data.__proto__ = proto
}
proxy (vue3)

新版的 vue3 应用 es6 的 proxy 形式来解决这个问题,
首先 proxy 是反对数组的也就是数组是不须要做特地的解决.
对于深层监听也不须要应用递归的形式解决. 当 get 是判断值为对象做响应式解决返回就能够了. 比 vue2 大大的晋升了性能

function reactive(data) {if (typeof data !== 'object' || data === null) {return data}
    const observed = new Proxy(data, {get(target, key, receiver) {
            // Reflect 有返回值不报错
            let result = Reflect.get(target, key, receiver)

            // 多层代理
            return typeof result !== 'object' ? result : reactive(result) 
        },
        set(target, key, value, receiver) {effective()
            // proxy + reflect
            const ret = Reflect.set(target, key, value, receiver)
            return ret
        },

        deleteProperty(target,key){const ret = Reflect.deleteProperty(target,key)
            return ret
        }

    })
    return observed
}
退出移动版