proxy与Object.defineProperty

tech2024-01-04  75

proxy与Object.defineProperty

proxynew Proxy(obj, handler)改进handler的其他方法revocable Object.defineProperty详细介绍

proxy

Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等),等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

好比某个明星有个微博,但是微博每天评论太多,没时间处理,便交给了一个运营平台全权处理。运营平台便成为了明星的代理。这时,运营平台所表述的话就是明星的话。而粉丝是不能直接和明星进行交流的。

proxy便类似于运营平台,它决定了获取对象属性和设置对象属性时的条件,和操作对象及对象属性的方法。

new Proxy(obj, handler)

const ccg = {name:'ccg',age:20} const ccg2 = new Proxy(ccg,{ set(target,key,value,receiver){ return Reflect.set(target, key, value, receiver); }, get(target,key,receiver){ return Reflect.get(target, key, receiver); }, }) ccg2.name = 'ccg2'; console.log(ccg2); //Proxy {name: "ccg2", age: 20}

如上,ccg是一个普通的对象,通过new Proxy对ccg进行代理,生成了ccg2。

new Proxy是一个构造函数,第一个参数为需要代理的对象,第二个参数是一个对象,对象中最常用的就是上面的set和get事件。

const ccg = {name:'ccg',age:20} const ccg2 = new Proxy(ccg,{ set(target,key,value,receiver){ target[key] = value; }, get(target,key,receiver){ return target[key]; }, }) ccg2.name = 'ccg2'; console.log(ccg2); //Proxy {name: "ccg2", age: 20}

target:代表当前代理的对象,在上面代码中代表ccg对象 key:需要进行设置或者获取的对象的键值 value:在set中进行设置的值 receiver:在set和get中都指的是proxy对象。

以上两种set和get内的写法本质上没什么区别都是可以进行代理。 Reflect是一个内置的对象,它提供拦截 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。Reflect的所有的方法都是静态的就和Math一样,目前它还没有静态属性。

改进

const Person = function(){} const ccg = {name:'ccg',age:20} const ccg2 = new Proxy(ccg,{ set(target,key,value,receiver){ if(target.hasOwnProperty(key)){ return Reflect.set(target, key, value, receiver); }else{ throw new Error('属性不存在') } }, get(target,key,receiver){ if(target.hasOwnProperty(key)){ return Reflect.get(target, key, receiver); }else{ throw Error('属性不存在') } }, getPrototypeOf(){ return Person.prototype } }) ccg2.name = 'ccg2'; console.log(ccg2); // Proxy {name: "ccg2", age: 20} console.log(Object.getPrototypeOf(ccg2)); // Person

如上,我们将Person看做一个构造函数,利用new Proxy进行代理,在set和get中进行key检查,如果发现ccg中没有为key的键值,则直接报错,否则就正常运行,通过getPrototypeOf方法,将ccg2 的原型对象改为构造函数Person的原型对象。

handler的其他方法

// 在读取代理对象的原型时触发该操作,比如在执行 handler.getPrototypeOf() Object.getPrototypeOf(proxy) // 在设置代理对象的原型时触发该操作,比如在执行 handler.setPrototypeOf() Object.setPrototypeOf(proxy, null) // 在判断一个代理对象是否是可扩展时触发该操作,比如在执行 handler.isExtensible() Object.isExtensible(proxy) // 在让一个代理对象不可扩展时触发该操作,比如在执行 handler.preventExtensions() Object.preventExtensions(proxy) // 在获取代理对象某个属性的属性描述时触发该操作,比如在执行 handler.getOwnPropertyDescriptor() Object.getOwnPropertyDescriptor(proxy, "foo") // 在定义代理对象某个属性时的属性描述时触发该操作,比如在执行 handler.defineProperty() Object.defineProperty(proxy, "foo", {}) // 在判断代理对象是否拥有某个属性时触发该操作,比如在执行 "foo" in proxy 时。 handler.has() // 在读取代理对象的某个属性时触发该操作,比如在执行 proxy.foo 时。 handler.get() // 在给代理对象的某个属性赋值时触发该操作,比如在执行 proxy.foo = 1 时。 handler.set() // 在删除代理对象的某个属性时触发该操作,比如在执行 delete proxy.foo 时。 handler.deleteProperty() // 在获取代理对象的所有属性键时触发该操作,比如在执行 handler.ownKeys() Object.getOwnPropertyNames(proxy) 时。 // 在调用一个目标对象为函数的代理对象时触发该操作,比如在执行 proxy() 时 handler.apply() // 在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行new proxy() 时。 handler.construct()

revocable

Proxy只有一个静态方法revocable(target, handler)可以用来创建一个可撤销的代理对象。两个参数和构造函数的相同。它返回一个包含了所生成的代理对象本身以及该代理对象的撤销方法的对象。

var revocable = Proxy.revocable({}, { get(target, name) { return "[[" + name + "]]"; } });
最新回复(0)