JavaScript 代理是一种对象,允许你包装一个特定的对象,并定制该对象的基础操作,比如获取和设置对象属性。简而言之,使用代理对象,可以向对象添加自定义行为。代理常用来实现诸如记录、缓存和安全性等功能。
在 JavaScript 中,我们可以使用 Proxy() 构造器创建代理对象。构造器接受两个参数——目标对象和处理器对象。它返回一个新的针对目标对象的代理对象。
语法
以下是创建代理对象的语法:
const obj = new Proxy(targetObj, Handler);
在上面的语法中,我们使用了带有 new 关键字的 Proxy() 构造器。
参数
Proxy 构造器需要两个参数:
-
targetObj - 这是你想要为其创建代理对象并定制其默认行为的目标对象。
-
Handler - 这是一个包含定制目标对象行为的功能的对象。
示例
在下面的示例中,person 对象包含了 name 和 age 属性。
我们为 person 对象定义了一个名为 proxyObj 的代理对象。同时,我们将处理器对象作为 Proxy() 构造器的一个参数传递。
在处理器对象中,我们定义了访问对象属性的 getter。getter 检查对象是否包含你要查找的属性。如果包含,则返回属性值。否则,返回一条消息说对象不包含该属性。
<html>
<body>
<div id="demo1">人的名字是: </div>
<div id="demo2">人的身高是: </div>
<script>
const person = {
name: "Same",
age: 32,
}
const handler = {
get: function(object, property) {
return object[property] ? object[property] : '对象不包含该属性。';
}
}
const proxyObj = new Proxy(person, handler);
document.getElementById("demo1").innerHTML += proxyObj.name;
document.getElementById("demo2").innerHTML += proxyObj.height;
</script>
</body>
</html>
输出:
人的名字是: Same
人的身高是: 对象不包含该属性。
当你从对象中访问不存在的属性时,默认情况下返回 undefined。在这里,我们定制了对象的默认行为,返回一个更友好的信息。
如果你在创建代理对象时传入空的处理器对象,那么代理对象将与原始对象表现相同。
JavaScript 代理处理器
JavaScript 中有多个可用的代理处理器,下面覆盖了一些。代理处理器用于重写对象的默认行为。
JavaScript get() 代理处理器
get() 代理处理器允许你更改对象的属性访问行为。
语法
以下是使用 get() 代理处理器的语法:
get(target, property, receiver)
参数
示例
在下面的代码中,watch 对象包含了 brand、color 和 price 属性。我们为 watch 对象创建了代理。
处理器对象包含 get() 处理器,并返回属性值,如果不是 null。否则,返回一个易读的消息。
<html>
<body>
<div id="output1">品牌: </div>
<div id="output2">价格: </div>
<script>
const watch = {
brand: "Casio",
color: "Blue",
price: null,
}
const handler = {
get(object, property) {
return object[property] != null ? object[property] : "属性为空。";
}
}
const watchProxy = new Proxy(watch, handler);
document.getElementById("output1").innerHTML += watchProxy.brand;
document.getElementById("output2").innerHTML += watchProxy.price;
</script>
</body>
</html>
输出:
品牌: Casio
价格: 属性为空。
JavaScript set() 代理处理器
set() 代理处理器用于更改更新对象属性的默认行为。
语法
以下是使用 set() 代理处理器的语法:
set(target, property, value, receiver)
参数
示例
在下面的代码中,处理器对象包含 set() 代理处理器。set() 处理器检查属性是否等于 price。如果是,则更新属性值为新值。否则,将 Not Available 设置为对象属性。
<html>
<body>
<p id="demo"> </p>
<script>
const output = document.getElementById("demo");
const watch = {
brand: "Casio",
color: "Blue",
price: null,
}
const handler = {
set(object, property, value) {
if (property === "price") {
object[property] = value;
}
else {
object[property] = "Not Available";
}
}
}
const watchProxy = new Proxy(watch, handler);
watchProxy.price = 2000;
watchProxy.dial = "Round";
output.innerHTML += "价格: " + watchProxy.price + "<br>";
output.innerHTML += "表盘: " + watchProxy.dial + "<br>";
</script>
</body>
</html>
输出:
价格: 2000
表盘: Not Available
JavaScript apply() 代理处理器
apply() 代理处理器用于更改函数调用的默认行为。
语法
以下是使用 apply() 代理处理器的语法:
apply(target, thisArg, argumentsList)
参数
-
-
thisArg - 指向函数体中应使用 this 关键字访问的上下文。
-
argumentsList - 需要传递给函数的参数列表。
示例
在下面的代码中,getDetails 是为 getWatchDetails() 函数创建的代理对象。处理器对象包含 apply() 方法,并调用目标函数。
我们通过传递 watch 对象作为参数来调用 getDetails() 代理。
<html>
<body>
<p id="output"> </p>
<script>
const watch = {
brand: "Casio",
color: "Blue",
price: 2000,
}
const getWatchDetails = function(watch) {
return `品牌: ${watch.brand},
颜色: ${watch.color},
价格: ${watch.price}`;
}
const getDetails = new Proxy(getWatchDetails, {
apply(target, thisArg, args) {
return target(...args).toUpperCase();
}
});
document.getElementById("output").innerHTML += getDetails(watch);
</script>
</body>
</html>
输出:
品牌: CASIO, 颜色: BLUE, 价格: 2000
JavaScript 中代理对象的应用
这里我们解释了使用代理对象的好处,并附带了例子。
用于验证
在更新属性值或向对象添加新属性时,你可以使用 JavaScript 中的代理对象来进行验证。
示例
在下面的代码中,numbers 对象包含了 num1、num2 和 num3 属性。set() 代理处理器检查新值是否大于当前值。如果是,则更新值。否则,保留旧值。
<html>
<body>
<p id="demo"> </p>
<script>
const output = document.getElementById("demo");
const numbers = {
num1: 10,
num2: 20,
num3: 30,
}
const handler = {
set(object, property, value) {
if (value > object[property]) {
object[property] = value;
}
}
}
const numberProxy = new Proxy(numbers, handler);
numberProxy.num1 = 20;
numberProxy.num2 = 10;
output.innerHTML += "num1: " + numbers.num1 + ", num2: " + numbers.num2;
</script>
</body>
</html>
输出:
num1: 20, num2: 20
JavaScript 中的代理(Proxy)用于访问控制
你还可以使用代理处理器来控制 JavaScript 中的对象访问。例如,你可以限制用户更新对象属性,将其设为只读。
示例
在下面的代码中,每当尝试更新对象属性值时,它会打印一条消息提示对象是只读的。
<html>
<body>
<p id="demo"> </p>
<script>
const output = document.getElementById("demo");
const numbers = {
num1: 10,
num2: 20,
num3: 30,
}
const handler = {
set(object, property, value) {
output.innerHTML += "对象是只读的。<br>";
}
}
const numberProxy = new Proxy(numbers, handler);
numberProxy.num1 = 20;
output.innerHTML += "num1: " + numberProxy.num1;
</script>
</body>
</html>
输出:
对象是只读的。
num1: 10
副作用
当任何人尝试访问或更新对象属性时,你可能会调用函数或类的方法。
示例
在下面的示例中,emailValidator() 函数检查电子邮件是否包含 @。如果包含,则返回 true。否则,返回 false。
在 set() 代理处理器中,我们根据 emailValidator() 函数的返回值更新属性值。
<html>
<body>
<p id="output"> </p>
<script>
const emails = {
email1: "abcd@gmail.com",
}
function emailValidator(email) {
if (email.includes("@")) {
return true;
} else {
return false;
}
}
const handler = {
set(object, property, value) {
if (emailValidator(value)) {
object[property] = value;
}
}
}
const emailProxy = new Proxy(emails, handler);
emailProxy.email1 = "nmc@gmail.com";
document.getElementById("output").innerHTML =
"email1: " + emailProxy.email1;
</script>
</body>
</html>
输出:
email1: nmc@gmail.com
然而,代理处理器的使用并不局限于这些,本教程无法涵盖每个使用场景。因此,你可以探索更多关于代理处理器的使用案例。
JavaScript 代理处理器列表
下面是所有 JavaScript 代理处理器的列表。
代理处理器方法
| 序号 |
代理处理器 |
描述 |
| 1 |
apply() |
改变函数调用的默认行为。 |
| 2 |
construct() |
捕获新建对象的行为。 |
| 3 |
defineProperty() |
改变定义新属性的行为。 |
| 4 |
deleteProperty() |
改变删除新属性的行为。 |
| 5 |
get() |
改变访问对象属性的行为。 |
| 6 |
getOwnPropertyDescriptor() |
捕获对象的 getOwnPropertyDescriptor() 方法。 |
| 7 |
getPrototypeOf() |
捕获内部方法。 |
| 8 |
has() |
操控检查对象是否包含属性的行为。 |
| 9 |
isExtensible() |
捕获对象的 isExtensible() 方法。 |
| 10 |
ownKeys() |
改变 ownKeys() 方法的行为。 |
| 11 |
preventExtensions() |
捕获阻止对象扩展的行为。 |
| 12 |
set() |
改变向对象添加新属性或更新属性值的默认行为。 |
| 13 |
setPrototypeOf() |
自定义 Object.setPrototypeOf() 方法。 |
构造器
| 序号 |
构造器 |
描述 |
| 1 |
Proxy() |
用于创建一个代理对象。 |
静态方法
| 序号 |
方法 |
描述 |
| 1 |
revocable() |
类似于 Proxy() 构造器,用于创建一个新的代理对象。 |