响应式定义
响应式就是数据模型发生变化可以发出相应响应, 比如调用一个函数
功能实现
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
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。