JavaScript Proxies 怎么用?代理对象如何拦截属性访问?

文章导读
Previous Quiz Next JavaScript 中的 Proxy JavaScript 中的 proxies 是允许你包装特定对象并自定义对象基本操作(如获取和设置对象属性)的对象。简而言之,使用 proxy 对象,你可以为对象添加自定义行为。proxies 用
📋 目录
  1. A JavaScript 中的 Proxy
  2. B JavaScript Proxy Handlers
  3. C JavaScript 中 Proxy 对象的用途
  4. D JavaScript Proxy 处理程序列表
A A

JavaScript - Proxies



Previous
Quiz
Next

JavaScript 中的 Proxy

JavaScript 中的 proxies 是允许你包装特定对象并自定义对象基本操作(如获取和设置对象属性)的对象。简而言之,使用 proxy 对象,你可以为对象添加自定义行为。proxies 用于实现日志记录、缓存和安全性等功能。

我们可以使用 JavaScript 中的 Proxy() 构造函数创建一个 proxy 对象。该构造函数接受两个参数:target object 和 handler object。它为 target object 返回一个新的 proxy 对象。

语法

以下是在 JavaScript 中创建 proxy 对象的语法 −

const obj = new Proxy(targetObj, Handler);

在上述语法中,我们使用了带有 new 关键字的 Proxy() 构造函数。

参数

Proxy 构造函数接受两个参数。

  • targetObj − 这是你要为其创建 proxy 对象并自定义其默认行为的 target object。

  • Handler − 这是一个包含自定义 target object 行为功能的对象。

示例

在下面的示例中,person 对象包含 name 和 age 属性。

我们为 person 对象定义了名为 proxyObj 的 proxy 对象。同时,我们将 handler 对象作为 Proxy() 构造函数的参数传递。

在 handler 对象中,我们定义了 getters 来访问对象属性。getters 检查对象是否包含你正在查找的属性。如果是,则返回属性值;否则,返回一条消息,表明对象不包含该属性。

<html>
<body>
   <div id = "demo1">The name of the person is: </div>
   <div id = "demo2">The height of the person is: </div>
   <script>
      const person = {
         name: "Same",
         age: 32,
      }
      const handler = {
         // 定义 getters
         get: function (object, property) {
            return object[property] ? object[property] : 
            'Object doesnt contain the property.';
         }
      }
      const proxyObj = new Proxy(person, handler);
      document.getElementById("demo1").innerHTML += proxyObj.name;
      document.getElementById("demo2").innerHTML += proxyObj.height;
   </script>
</body>
</html>

输出

The name of the person is: Same
The height of the person is: Object doesnt contain the property.

当你访问对象中不存在的属性时,它会返回 undefined。在这里,我们自定义了对象的默认行为,返回一个友好且易读的消息。

如果你在创建 proxy 对象时传递空 handler 对象,proxy 对象将与原始对象行为相同。

JavaScript Proxy Handlers

JavaScript 中有多种可用的 proxy handlers,我们在下面介绍了一些。proxy handlers 用于覆盖对象的默认行为。

JavaScript get() proxy handler

JavaScript 中的 get() proxy handler 允许您更改对象的属性访问行为。

语法

按照下面的语法使用 get() proxy handler 与 proxy 对象。

get(target, property, receiver)

参数

  • target − 目标对象。

  • property − 需要访问其值的属性。

  • receiver − proxy 对象本身。

示例

在下面的代码中,watch 对象包含 brand、color 和 price 属性。我们为 watch 对象创建了 proxy。

handler 对象包含 get() handler,如果属性值不为 null,则返回属性值;否则,返回一条可读的消息。

<html>
<body>
   <div id = "output1">Brand:  </div>
   <div id = "output2">Price:  </div>
   <script>
      const watch = {
         brand: "Casio",
         color: "Blue",
         price: null,
      }

      const handler = {
         get(object, property) {
            return object[property] != null ? object[property] : "Property is null.";
         }
      }
      const wathcProxy = new Proxy(watch, handler);
      document.getElementById("output1").innerHTML += wathcProxy.brand;
      document.getElementById("output2").innerHTML += wathcProxy.price;
   </script>
</body>
</html>

输出

Brand: Casio
Price: Property is null.

JavaScript set() proxy handler

JavaScript 中的 set() proxy handler 用于更改更新对象属性的默认行为。

语法

按照下面的语法使用 set() proxy handler。

set(target, property, value, receiver)

参数

  • target − 目标对象。

  • property − 要更改其值的属性。

  • value − 更新后的值。

  • receiver − proxy 对象本身。

示例

在下面的代码中,handler 对象包含 set() proxy handler。set() handler 检查属性是否等于 '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 wathcProxy = new Proxy(watch, handler);
      wathcProxy.price = 2000;
      wathcProxy.dial = "Round";
      output.innerHTML += "Price: " + wathcProxy.price + "<br>";
      output.innerHTML += "Dial: " + wathcProxy.dial + "<br>";
   </script>
</body>
</html>

输出

Price: 2000
Dial: Not Available

JavaScript apply() proxy handler

apply() proxy handler 用于更改函数调用的默认行为。

语法

按照下面的语法使用 apply() proxy handler。

apply(target, thisArg, arguments)

参数

  • target − 需要执行的目标函数。

  • thisArg − 指代函数体中使用 this 关键字访问其元素的上下文。

  • arguments − 传递给函数的参数数组。

示例

在下面的代码中,getDetails 是为 getWatchDetails() 函数创建的 proxy 对象。handler 对象包含 apply() 方法并调用目标函数。

我们通过传递 watch 对象作为参数调用了 getDetails() proxy。

<html>
<body>
   <p id = "output"> </p>
   <script>
      const watch = {
         brand: "Casio",
         color: "Blue",
         price: 2000,
      }
      const getWatchDetails = function (watch) {
         return `Brand: ${watch.brand},  
         Color: ${watch.color}, 
         price: ${watch.price}`;
      }
      const getDetails = new Proxy(getWatchDetails, {
         apply(target, thisArg, args) {
            return target(...args).toUpperCase();
         }
      });
      document.getElementById("output").innerHTML += getDetails(watch);
   </script>
</body>
</html>

输出

BRAND: CASIO, COLOR: BLUE, PRICE: 2000

JavaScript 中 Proxy 对象的用途

在这里,我们通过示例解释了使用 proxy 对象的优势。

用于验证

你可以在 JavaScript 中使用 proxy 对象,在更新属性值或向对象添加新属性时验证属性值。

示例

在下面的代码中,numbers 对象包含 num1、num2 和 num3 属性。set() proxy handler 检查新值是否大于当前值。如果是,则更新值。否则,保留旧值。

<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

用于访问控制

你还可以使用 proxy handler 来控制 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 += "Object is read-only.<br>"
         }
      }
      const numberProxy = new Proxy(numbers, handler);
      numberProxy.num1 = 20;
      output.innerHTML += "num1: " + numberProxy.num1;
   </script>
</body>
</html>

输出

Object is read-only.
num1: 10

副作用

当有人尝试访问或更新对象属性时,你可以调用函数或 class 方法。

示例

在下面的示例中,emailValidator() 函数检查 email 是否包含 '@'。如果是,则返回 true。否则,返回 false。

在 set() proxy handler 中,我们根据 emailValidator() 函数的返回值更新属性值。

<html>
<body>
   <p id = "output"> </p>
   <script>
      const emails = {
         email1: "abcd@gmail.com",
      }
      // 用于验证 email 的函数
      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

然而,proxy handler 的用法并不仅限于此,本教程无法涵盖所有用例。因此,你可以探索更多 proxy handler 的用例。

JavaScript Proxy 处理程序列表

在这里,我们列出了 JavaScript 中的所有 proxy handlers。

Proxy Handler 方法

序号 Proxy Handler 描述
1 apply() 它改变了函数调用的默认行为。
2 construct() 捕获新对象的构造。
3 defineProperty() 改变定义新属性的行为。
4 deleteProperty() 改变删除属性的行为。
5 get() 改变访问对象属性的行为。
6 getOwnPropertyDescriptor() 用于捕获对象的 getOwnPropertyDescriptor() 方法。
7 getPrototypeOf() 捕获内部方法。
8 has() 用于操纵检查对象是否包含属性的行为。
9 isExtensible() 用于捕获 Object 的 isExtensible() 方法。
10 ownKeys() 改变 ownKeys() 方法的行为。
11 preventExtension() 用于捕获阻止对象扩展的行为。
12 set() 改变添加新属性或更新对象属性值的默认行为。
13 setPrototypeOf() 用于自定义 Object.setPrototypeOf() 方法。

构造函数

序号 Constructor 描述
1 Proxy() 用于创建 proxy 对象。

静态方法

序号 Method 描述
1 revocable() 也用于创建类似于 Proxy() 构造函数的新 proxy 对象。