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() 构造器,用于创建一个新的代理对象。 |