Proxy() 构造函数
Proxy()
构造函数用于创建 Proxy
对象。
语法
new Proxy(target, handler)
可以使用 Proxy()
构造函数来创建一个新的 Proxy
对象。构造函数接收两个必须的参数:
target
是要创建的对象,即要使用Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。handler
是定义了代理的自定义行为的对象,其属性是定义了在对代理执行操作时的行为的函数。
注意:Proxy()
只能通过 new
关键字来调用。如果不使用 new
关键字调用,则会抛出 TypeError
。
Proxy对象
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
语法
const p = new Proxy(target, handler)
handler对象的方法
handler
对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy
的各个捕获器(trap
)。
所有的捕捉器都是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
一个空的处理器(handler
)将会创建一个与被代理对象行为几乎完全相同的代理对象。通过在 handler
对象上定义一组函数,你可以自定义被代理对象的一些特定行为。
如果在 handler
中存在相应的捕捉器,则它将运行,并且 Proxy
有机会对其进行处理,否则将直接对 target
进行处理。
示例:
let target = {
};
let proxy = new Proxy(target, {
}); // 空的 handler 对象
proxy.test = 5; // 写入 proxy 对象
console.log('target:', target, 'proxy:', proxt); // target和proxy中都有test属性!
console.log(target.test); // 5,test 属性出现在了 target 中!
console.log(proxy.test); // 5,我们也可以从 proxy 对象读取它
for(let key in proxy) console.log(key); // test,迭代也正常工作
在这个示例中, handler
对象为空,没有捕捉器,所有对 proxy
的操作都直接转发给了 target
。
- 写入操作
proxy.test = 5
会将值写入 target。 - 读取操作
proxy.test
会从target
返回对应的值。 - 迭代
proxy
会从target
返回对应的值。
此时,proxy
是一个target
的透明包装器(wrapper)。它没有自己的属性。如果handler
为空,则透明地将操作转发给target
。
对于对象的大多数操作,JavaScript 规范中有一个所谓的“内部方法”,它描述了最底层的工作方式。
Proxy
捕捉器会拦截 对底层被代理对象的调用。
例如,通过定义 set()
可以自定义写入被代理对象的属性;通过定义 get()
可以自定义被代理对象的属性访问器。
常见的拦截操作和对应的捕捉器函数有:
set(target, propKey, value, receiver)
:拦截对象的设置属性操作,返回一个布尔值表示是否设置成功。get(target, propKey, receiver)
:拦截对象的读取属性操作,返回属性值。has(target, propKey)
:拦截对象的in
操作符,返回一个布尔值表示对象是否包含该属性。deleteProperty(target, propKey)
:拦截对象的 delete 操作符,返回一个布尔值表示是否删除成功。ownKeys()
:Object.getOwnPropertyNames
方法和Object.getOwnPropertySymbols
方法的捕捉器函数。getPrototypeOf()
:Object.getPrototypeOf
方法的捕捉器。setPrototypeOf()
:Object.setPrototypeOf
方法的捕捉器。isExtensible()
:Object.isExtensible
方法的捕捉器。preventExtensions()
:Object.preventExtensions
方法的捕捉器。getOwnPropertyDescriptor()
:Object.getOwnPropertyDescriptor
方法的捕捉器。defineProperty()
:Object.defineProperty
方法的捕捉器。apply(target, thisArg, args)
:拦截函数的调用操作,返回调用结果。construct(target, args, newTarget)
:拦截new
操作符,返回一个对象。
handler.set()
handler.set()
方法是设置属性值操作的捕获器。文档请看mdn
语法
new Proxy(target, {
set(target, property, value, receiver) {
}
});
handler.set()
方法用于拦截设置属性值的操作。this
绑定在 handler
对象上。
以下是传递给 set()
方法的参数:
target
目标对象。该对象被作为第一个参数传递给new Proxy
。property
目标属性名称(将被设置的属性名或 Symbol)。value
目标属性值。receiver
最初接收赋值的对象。通常是proxy
本身,但handler
的set
方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是proxy
本身)。
返回值:
- 返回
true
代表属性设置成功。 - 在严格模式下,如果
set()
方法返回false
,那么会抛出一个TypeError
异常。
使用示例
let numbers = [];
numbers = new Proxy(numbers, {
// (*)
set(target, prop, val) {
// 拦截写入属性操作
if (typeof val == 'number') {
target[prop] = val;
return true; // 此处必须要return true,表示属性设置成功
} else {
return false;
}
}
});
numbers.push(1); // 添加成功
numbers.push("test"); // TypeError(proxy 的 'set' 返回 false)
如果写入操作(setting)成功,set
捕捉器应该返回 true
,否则返回 false
(触发 TypeError
)。
handler.get()
handler.get()
方法用于拦截对象的读取属性操作。文档请看mdn
语法
var p = new Proxy(target, {
get: function (target, property, receiver) {
},
});
以下是传递给 get()
方法的参数:
target
目标对象。该对象被作为第一个参数传递给new Proxy
。property
目标属性名称。receiver
Proxy
或者继承Proxy
的对象。
返回值:
get
方法可以返回任何值。
使用示例
let numbers = [0, 1, 2];
numbers = new Proxy(numbers, {
get(target, prop) {
if (prop in target) {
return target[prop];
}
}
});
alert( numbers[1] ); // 1
alert( numbers[123] ); // undefined(没有这个数组项)
如果获取数组中不存在的值,会得到 undefined
。
在get
捕获器,可以给不存在的值一个默认值。
handler.deleteProperty()
handler.deleteProperty()
方法用于拦截对对象属性的 delete 操作。
deleteProperty语法
var p = new Proxy(target, {
deleteProperty: function (target, property) {
},
});
参数
- target
目标对象。 - property
待删除的属性名。
返回值
deleteProperty
必须返回一个 Boolean
类型的值,表示了该属性是否被成功删除。
使用示例