Proxy、Object.defineProperty()
machao07 opened this issue · comments
1、Proxy
Proxy 劫持的是整个对象
Proxy 两个参数
target
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理handler
一个通常以函数作为属性的对象,用来定制拦截行为
const origin = {}
const obj = new Proxy(origin, {
get: function (target, propKey, receiver) {
return '10'
}
});
obj.a // 10
obj.b // 10
origin.a // undefined
origin.b // undefined
handler 对象常用方法
方法 | 描述 |
---|---|
handler.has() | in 操作符的捕捉器 |
handler.get() | 属性读取操作的捕捉器 |
handler.set() | 属性设置操作的捕捉器 |
handler.deleteProperty() | delete 操作符的捕捉器 |
handler.ownKeys() | Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器 |
handler.apply() | 函数调用操作的捕捉器 |
handler.construct() | new 操作符的捕捉器 |
2、Object.defineProperty()
直接在一个对象上
定义一个新属性
,或者修改一个对象的现有属性
,并返回此对象
defineProperty 三个参数
obj
要定义属性的对象prop
要定义或修改的属性的名称或 Symboldescriptor
要定义或修改的属性描述符
const obj = {}
Object.defineProperty(obj, "a", {
value : 1,
writable : false, // 是否可写
configurable : false, // 是否可配置
enumerable : false // 是否可枚举
})
obj.a = 2 // 无效
delete obj.a // 无效
for(key in obj){
console.log(key) // 无效
}
vue2 双向绑定实现
- 通过 defineProperty 的 getter,setter 来实现的
- 双向绑定的流程 观察到对象属性的变更,再去通知更新视图就好
const obj = {};
Object.defineProperty(obj, 'a', {
set(val) {
console.log(`开始设置新值: ${val}`)
},
get() {
console.log(`开始读取属性`)
return 1;
},
writable : true
})
obj.a = 2 // 开始设置新值: 2
obj.a // 开始获取属性
源码
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// ...
if (Dep.target) {
// 收集依赖
dep.depend()
}
return value
},
set: function reactiveSetter (newVal) {
// ...
// 通知视图更新
dep.notify()
}
})
对象新增属性不更新原因
data init 是在生命周期 created 之前的操作,会对 data 绑定一个观察者 Observer,之后 data 中的字段更新都会通知依赖收集器Dep触发视图更新
在 Observer data 时,新增属性并不存在,自然就不会有 getter, setter
对比
Proxy
作为新标准将受到浏览器厂商重点持续的性能优化
- Proxy
能观察的类型比 defineProperty
更丰富
-
Proxy
不兼容IE,也没有polyfill
,defineProperty
能支持到IE9 -
Object.definedProperty
是劫持对象的属性,新增元素需要再次definedProperty
。而 Proxy 劫持的是整个对象,不需要做特殊处理 -
使用
defineProperty
时,我们修改原来的 obj 对象就可以触发拦截,而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截