Proxy介绍

Proxy 让我们可以对任何对象的绝大部分行为进行监听和干涉,实现更多的自定义程序行为。
用法:new Proxy(target, handler)。
   Proxy 通过设置行为监听方法来捕获程序对对应对象的行为。

	const obj = {};
	const proxy = new Proxy(obj, {
	    // ...
	})

Proxy 的构造器接受两个参数,第一个参数为需要进行包装的目标对象,第二个参数则为用于监听目标对象行为的监听器,其中监听器可以接受一些参数以监听相对应的程序行为。
监听属性、参数及监听内容

属性值监听器参数监听内容
has(target, prop)监听 in 语句的使用
get(target, prop, reciver)监听目标对象的属性读取
set(target, prop, value, reciver)监听目标对象的属性赋值
deleteProperty(target, prop)监听 delete 语句对目标对象的删除属性行为
ownKeys(target)监听 Object.getOwnPropertyName() 的读取
apply(target, thisArg, arguments)监听目标函数(作为目标对象)的调用行为
construct(target, arguments, newTarget)监听目标构造函数(作为目标对象)利用 new 而生成实例的行为
getPrototypeOf(target)监听 Objext.getPrototypeOf() 的读取
setPrototypeOf(target, prototype)监听 Objext.setPrototypeOf() 的调用
isExtensible(target)监听 Objext.isExtensible() 的读取
preventExtensions(target)监听 Objext.preventExtensions() 的读取
getOwnPropertyDescriptor(target, prop)监听 Objext.getOwnPropertyDescriptor() 的调用
defineProperty(target, property, descriptor)监听 Object.defineProperty() 的调用

has

可以通过为 Proxy 的 handler 定义 has 监听方法,来监听程序通过 in 语句来检查一个字符串或数字是否为该 Proxy 的目标对象中某个属性的属性键的过程。

const p = new Proxy({}, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return true;
    }
})

console.log('foo' in p);
// Checking "foo" is in the target or not
// true

该监听方法有两个需要注意的地方,如果遇到这两种情况,便会抛出 TypeError 错误。

1.当目标对象被其他程序通过 Object.preventExtensions() 禁用了属性拓展 (该对象无法再增加新的属性,只能对当前已有的属性进行操作,包括读取、操作和删除,但是一旦删除就无法再定义) 功能,且被检查的属性键确实存在与目标对象中,该监听方法便不能返回 false。

const obj = {foo: 1};

Object.preventExtensions(obj);

const p = new Proxy(obj, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return false; 
    }
})

console.log('foo' in p);   
//抛出Uncaught TypeError: 

2.当被检查的属性键存在与目标对象中,且该属性的 configurable 配置是 false 时,该监听方法不能返回 false。

const obj = {};

Object.defineProperty(obj, 'foo', {
    configurable: false,
    value: 10
})

const p = new Proxy(obj, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return false;
    }
})

console.log('foo' in p);
//抛出Uncaught TypeError: 

get

Getter只能对已知的属性键进行监听,而无法对所有属性读取行为进行拦截,而 Proxy 可以通过设定 get 监听方法,拦截和干涉目标对象的所有属性读取行为。

const obj = {foo: 1};
const p = new Proxy(obj, {
    get(target, prop){
        console.log(`Program is trying to fetch the property "${prop}".`);
        return target[prop];
    }
})

alert(p.foo);  // Program is trying to fetch the property "foo".
alert(p.something);    // Program is trying to fetch the property "something".

这个监听方法也存在需要注意的地方——当目标对象被读取属性的 configurable 和 writable 属性都为 false 时,监听方法最后返回的值必须与目标对象的原属性值一致。

const obj = {};

Object.defineProperty(obj, 'foo', {
    configurable: false,
    value: 10,
    writable: false
})

const p = new Proxy(obj, {
    get(target, prop){
        return 20;
    }
})

console.log(p.foo);

set

handler.set 用于监听目标对象的所有属性赋值行为。注意,如果目标对象自身的某个属性是不可写也不可配置的,那么 set 不得改变这个属性的值,只能返回同样的值,否则报错。

const obj = {};
const p = new Proxy(obj, {
    set(target, prop, value){
        console.log(`Setting value "${value}" on the key "${prop}" in the target object`);
        target[prop] = value;
        return true;
    }
})

p.foo = 1;  
// Setting value "1" on the key "foo" in the target object

apply

handler.apply , Proxy 也为作为目标对象的函数提供了监听其调用行为的属性。

const sum = function(...args) {
  return args
    .map(Number)
    .filter(Boolean)
    .reduce((a, b) => a + b);

}

const p = new Proxy(sum, {
  apply(target, thisArg, args) {
    console.log(`Function is being called with arguments [${args.join()}] and context ${thisArg}`);
    return target.call(thisArg, ...args);
  }
})

console.log(p(1, 2, 3));
// Function is being called with arguments [1,2,3] and context undefined
// 6

construct

handler.construct, Proxy 也可以将类作为目标监听对象,并监听其通过 new 语句来生产新实例的行为,这同样可以使用再作为构造器的构造函数上。

class Foo{};

const p = new Proxy(Foo, {
    construct(target, args, newTarget){
        return {arguments: args}    // 这里返回的结果会是 new 所得到的实例
    }
});

const obj = new p(1, 2, 3);
console.log(obj.arguments);  // [1, 2, 3]

创建可解除 Proxy 对象

用法:Proxy.revocable(target, handler) : (proxy, revoke)。

const obj = {foo: 10};
const revocable = Proxy.revocable(obj, {
    get(target, prop){
        return 20;
    }
})
const proxy = revocable.proxy;
console.log(proxy.foo); // 20
revocable.revoke();
console.log(proxy.foo); 
// TypeError: Cannot perform 'get' on a proxy that has been revoked

Proxy.revocable(target, handler) 会返回一个带有两个属性的对象,其中一个 proxy 便是该函数所生成的可解除 Proxy 对象,而另一个 revoke 则是将刚才的 Proxy 对象解除的解除方法。

### 回答1: JavaScript 中的 `Proxy` 是一个对象,它可以用来拦截对其他对象的访问,从而实现自定义的行为。 `Proxy` 可以代理一个对象的读写操作,包括: - 读取对象属性,如 `obj.foo` - 设置对象属性,如 `obj.foo = 'bar'` - 调用对象方法,如 `obj.baz()` - 删除对象属性,如 `delete obj.foo` - 等等 通过代理对象,我们可以对对象的访问进行拦截并实现自定义的行为。 比如说,我们可以使用 `Proxy` 对象来实现数据绑定、数据校验、数据缓存、访问控制等功能。 ``` const target = {}; const handler = { get: function(target, prop, receiver) { console.log(`Getting property ${prop}`); return Reflect.get(target, prop, receiver); }, set: function(target, prop, value, receiver) { console.log(`Setting property ${prop} to ${value}`); return Reflect.set(target, prop, value, receiver); } }; const proxy = new Proxy(target, handler); proxy.foo = 'bar'; console.log(proxy.foo); ``` 以上代码创建了一个空的目标对象 `target` 和一个代理处理程序 `handler`。当我们对代理对象进行读写操作时,会触发代理处理程序的 `get` 和 `set` 方法,从而实现自定义的行为。 `Proxy` 对象是 ECMAScript 6 中新增的特性,且不是所有浏览器都支持。请注意,如果你的 ### 回答2: Proxy是JavaScript中的一个内置对象,它允许你在访问一个对象之前拦截并定义自定义的行为。通过Proxy,你可以修改某个对象的默认行为,以自定义其操作。 Proxy的基本用法是,创建一个代理实例,并传入两个参数:目标对象和处理程序对象。目标对象是被代理的对象,处理程序对象是一个包含要拦截方法的对象。处理程序对象中的方法将在对目标对象进行操作时被调用。 Proxy支持一系列的方法拦截操作,包括get、set、has、deleteProperty、apply等等。例如,通过拦截get方法,可以对目标对象的属性进行自定义操作,比如添加一层访问权限验证。 Proxy还支持trap的代理扩展。这允许在对象未定义某个属性时触发一个函数。通过代理扩展,可以在对象中动态设置属性,并在需要时获取这些属性Proxy的另一个特性是原型代理。在原型代理中,Proxy不仅可以代理对象本身的操作,还可以代理对原型链的操作。这样,可以在访问原型链前后进行拦截和自定义操作。 Proxy还可以用于实现数据绑定和观察。通过在目标对象的get和set方法中添加额外的逻辑,可以实现数据改变时的通知和自动更新。 通过Proxy,我们可以实现更灵活和可扩展的代码,增强对象的行为和能力。然而,由于Proxy是一项较新的JavaScript特性,不是所有的浏览器都支持它。因此,在使用Proxy时需要注意浏览器的兼容性。 ### 回答3: Proxy是ES6引入的新功能,它可以用于对目标对象进行拦截、过滤和修改等操作,使得我们能够更加灵活地控制对象的访问。 Proxy有两个参数:目标对象和handler对象。目标对象可以是任意JavaScript对象,而handler对象用于定义所有可以对目标对象进行的操作。 通过Proxy,我们可以对目标对象的属性进行拦截和修改。handler对象可以包含get和set方法,当我们读取和设置目标对象的属性时,这些方法将会被调用。我们可以在这些方法中加入自己的逻辑,控制读取和设置的操作。 除了get和set方法外,handler对象还可以包含其他方法,例如apply方法可以拦截函数的调用,has方法可以拦截in操作符的判断,deleteProperty方法可以拦截delete操作符的操作,等等。 Proxy还可以用于改变目标对象的行为。比如我们可以在handler对象的get方法中,返回一个新的Proxy对象,从而实现对目标对象的递归访问。 另外,Proxy还提供了一些内置的静态方法,例如Proxy.revocable可以创建一个可撤销的Proxy对象,Proxy.create可以创建一个空的Proxy对象。 总之,Proxy在JavaScript中提供了一种灵活的方式来对对象进行拦截和修改,使得我们能够更加方便地进行一些高级的操作和逻辑控制。然而需要注意的是,Proxy并不是完全替代原始对象的,它只是对原始对象的一种补充和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值