携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情
过去
Vue 利用 object.defineProperty来监测数据的读取和设置,在get中记录被依赖关系,在set时,通过依赖关系,触发更新,缺点是,在程序运行前,要将data属性全部递归遍历设置这个拦截规则,相当浪费性能,数组的检测更是要,重写Array.prototype上所有的变异方法,在方法执行之前做点事,执行后做点事,相当麻烦,es6Proxy的方法的出现,解决了Object.definePropery的痛点,在目标对象之前设一层"拦截",外界对该对象的访问,都必须通过这层拦截,可以对外界的访问进行过滤和改写,而且proxy根本不管对象内部嵌套多少层,因为他会在对象属性被读取时才处理,所以避免了遍历递归的性能问题。新增属性还要特殊处理。
get
使用 new Proxy 来创建proxy实例,这个构造函数接收两个参数,一个是target(目标对象,源对象,), 一个是handler(处理对象,常用的方法有get,set,deleteProperty,主要逻辑来自这里)
程序在读取对象属性的时候会执行get方法,get方法接收两个参数 target(目标对象),key(程序读取的属性),下面读取了代理对象三个属性,所以get方法执行了三次,target是obj,key是对应的属性名,所以结果和直接读原来对象的属性结果一样。
const obj = {
name: "tom",
age: 19,
sex: 12,
}
const p1 = new Proxy(obj, {
get(target, key) {
console.log(target, key);
return target[key];
},
})
console.log(p1.name,p1.age,p1.sex)
当然啥也不干就没必要劫持了,假设要给每个属性一个所属对象的前缀,"obj---",可以在get里加一个拼接就轻松实现了。这样一搞,所有读的属性都带前缀 obj---
...
get(target, key) {
console.log(target === obj, key);
return "obj---" + target[key];
},
set
当代理对象的属性被赋值时,会调用set方法,set方法接收三个参数,target(目标对象),key所设置的属性名,value设置的新的值
const obj = {
name: "tom",
age: 19,
sex: 12,
}
const p1 = new Proxy(obj, {
set(target, key, value) {
console.log(target, key, value)
target[key] = value
}
})
p1.age = '123'
可以拦截一下禁止设置对象,不能给属性设置为对象类型,
const obj = {
name: "tom",
age: 19,
sex: 12,
}
const p1 = new Proxy(obj, {
get(target, key) {
console.log(target === obj, key);
return "obj---" + target[key];
},
set(target, key, value) {
if (typeof value == 'object') {
console.log('不能赋值对象')
return;
}
target[key] = value
}
})
p1.age = {la:'xx'}
console.log(p1.age)
主要用的一般都这两,剩下的不怎么用
- 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)。