当前实现
proxy 对比 Object.defineProperty
Object.defineProperty 数据劫持只是对对象的属性进行劫持,无法监听新增属性和删除属性
1 2
| 深层对象的劫持需要一次性递归,性能不好 劫持数组时需要重写覆盖部分 Array.prototype 原生方法
|
补充:
其实在Object.defineProperty 本身是可用劫持数组的,本质上和劫持对象属性一样,只不过数组的属性是数组下标。
对象属性的新增需要重新劫持,所以,对于已经被劫持的数组,push的时候也需要进行重新添加劫持。
Vue 的实现中,从性能/体验的性价比考虑,放弃了这个特性。
proxy 数据劫持真正的对对象本身进行劫持,不好做polyfill
1 2 3
| 可以监听到对象新增、删除属性 只在 getter 时才对对象的下一层进行劫持(优化了性能) 能正确监听原生数组方法
|
proxy 优势
1.支持13种拦截操作,这是defineProperty不具备的
1 2 3 4 5 6 7 8 9 10 11 12 13
| get(target, propKey, receiver):拦截对象属性的读取,比如 proxy.foo 和 proxy['foo']。 set(target, propKey, value, receiver):拦截对象属性的设置,比如 proxy.foo = v 或 proxy['foo'] = v ,返回一个布尔值。 has(target, propKey):拦截 propKey in proxy 的操作,返回一个布尔值。 deleteProperty(target, propKey):拦截 delete proxy[propKey] 的操作,返回一个布尔值。 ownKeys(target):拦截 Object.getOwnPropertyNames(proxy) 、 Object.getOwnPropertySymbols(proxy) 、Object.keys(proxy) 、for...in 循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys() 的返回结果仅包括目标对象自身的可遍历属性。 getOwnPropertyDescriptor(target, propKey):拦截 Object.getOwnPropertyDescriptor(proxy, propKey) ,返回属性的描述对象。 defineProperty(target, propKey, propDesc):拦截 Object.defineProperty(proxy, propKey, propDesc) 、Object.defineProperties(proxy, propDescs) ,返回一个布尔值。 preventExtensions(target):拦截 Object.preventExtensions(proxy) ,返回一个布尔值。 getPrototypeOf(target):拦截 Object.getPrototypeOf(proxy) ,返回一个对象。 isExtensible(target):拦截 Object.isExtensible(proxy) ,返回一个布尔值。 setPrototypeOf(target, proto):拦截 Object.setPrototypeOf(proxy, proto) ,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如 proxy(...args)、proxy.call(object, ...args) 、proxy.apply(...) 。 construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如 new proxy(...args) 。
|
2.作为新标准,长远来看,JS引擎会继续优化 Proxy ,但 getter 和 setter 基本不会再有针对性优化。
相关链接
vue2深入响应式原理