摘要: 本教程将讲解 ES6 中的 JavaScript 代理对象。
什么是 JavaScript 代理对象
JavaScript 代理对象是一个 对象,它包裹另一个对象(目标对象)并拦截目标对象的基本操作。
基本操作可以是属性查找、赋值、枚举、函数调用等等。
创建代理对象
要创建新的代理对象,可以使用以下语法
let proxy = new Proxy(target, handler);
Code language: JavaScript (javascript)
在此语法中
target
– 是要包裹的对象。handler
– 是一个包含方法的对象,用于控制target
的行为。handler
对象内部的方法称为陷阱。
一个简单的代理示例
首先,定义一个名为user
的对象
const user = {
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
}
Code language: JavaScript (javascript)
其次,定义一个handler
对象
const handler = {
get(target, property) {
console.log(`Property ${property} has been read.`);
return target[property];
}
}
Code language: JavaScript (javascript)
第三,创建一个proxy
对象
const proxyUser = new Proxy(user, handler);
Code language: JavaScript (javascript)
proxyUser
对象使用user
对象来存储数据。proxyUser
可以访问user
对象的所有属性。

第四,通过proxyUser
对象访问user
对象的firstName
和lastName
属性
console.log(proxyUser.firstName);
console.log(proxyUser.lastName);
Code language: CSS (css)
输出
Property firstName has been read.
John
Property lastName has been read.
Doe
当您通过proxyUser
对象访问user
对象的属性时,handler
对象中的get()
方法会被调用。
第五,如果修改原始对象user
,更改会反映在proxyUser
中
user.firstName = 'Jane';
console.log(proxyUser.firstName);
Code language: JavaScript (javascript)
输出
Property firstName has been read.
Jane
类似地,proxyUser
对象的更改也会反映在原始对象(user
)中
proxyUser.lastName = 'William';
console.log(user.lastName);
Code language: JavaScript (javascript)
输出
William
代理陷阱
get()
陷阱
当通过代理对象访问target
对象的属性时,会触发get()
陷阱。
在前面的示例中,当proxyUser
对象访问user
对象的属性时,会打印出一条消息。
通常,您可以在访问属性时在get()
陷阱中开发自定义逻辑。
例如,您可以使用get()
陷阱为目标对象定义计算属性。计算属性是根据现有属性的值计算其值的属性。
user
对象没有fullName
属性,您可以使用get()
陷阱根据firstName
和lastName
属性创建fullName
属性
const user = {
firstName: 'John',
lastName: 'Doe'
}
const handler = {
get(target, property) {
return property === 'fullName' ?
`${target.firstName} ${target.lastName}` :
target[property];
}
};
const proxyUser = new Proxy(user, handler);
console.log(proxyUser.fullName);
Code language: JavaScript (javascript)
输出
John Doe
set()
陷阱
set()
陷阱控制设置target
对象属性时的行为。
假设用户的age
必须大于18。为了执行此约束,您可以开发一个set()
陷阱,如下所示
const user = {
firstName: 'John',
lastName: 'Doe',
age: 20
}
const handler = {
set(target, property, value) {
if (property === 'age') {
if (typeof value !== 'number') {
throw new Error('Age must be a number.');
}
if (value < 18) {
throw new Error('The user must be 18 or older.')
}
}
target[property] = value;
}
};
const proxyUser = new Proxy(user, handler);
Code language: JavaScript (javascript)
首先,将用户的age
设置为字符串
proxyUser.age = 'foo';
Code language: JavaScript (javascript)
输出
Error: Age must be a number.
Code language: JavaScript (javascript)
其次,将用户的年龄设置为16
proxyUser.age = '16';
Code language: JavaScript (javascript)
输出
The user must be 18 or older.
第三,将用户的年龄设置为21
proxyUser.age = 21;
没有发生错误。
apply()
陷阱
handler.apply()
方法是函数调用的陷阱。语法如下
let proxy = new Proxy(target, {
apply: function(target, thisArg, args) {
//...
}
});
Code language: JavaScript (javascript)
请参见以下示例
const user = {
firstName: 'John',
lastName: 'Doe'
}
const getFullName = function (user) {
return `${user.firstName} ${user.lastName}`;
}
const getFullNameProxy = new Proxy(getFullName, {
apply(target, thisArg, args) {
return target(...args).toUpperCase();
}
});
console.log(getFullNameProxy(user)); //
Code language: JavaScript (javascript)
输出
JOHN DOE
更多陷阱
以下是一些其他陷阱
construct
– 拦截new
运算符的使用getPrototypeOf
– 拦截对[[GetPrototypeOf]]
的内部调用setPrototypeOf
– 拦截对Object.setPrototypeOf
的调用isExtensible
– 拦截对Object.isExtensible
的调用preventExtensions
– 拦截对Object.preventExtensions
的调用getOwnPropertyDescriptor
– 拦截对Object.getOwnPropertyDescriptor
的调用
在本教程中,您学习了 JavaScript 代理对象,它用于包裹另一个对象,以更改该对象的根本行为。