Javascript 简明教程

JavaScript - Proxies

Proxy in JavaScript

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

我们可以使用 JavaScript 中的 Proxy() 构造函数创建代理对象。该构造函数接受两个参数——目标对象和处理程序对象。它为目标对象返回一个新的代理对象。

Syntax

以下是 JavaScript 中创建代理对象的语法——

const obj = new Proxy(targetObj, Handler);

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

Parameters

Proxy 构造函数采用两个参数。

  1. targetObj − 这是您想要为其创建代理对象并自定义其默认行为的目标对象。

  2. Handler − 这是包含自定义目标对象行为的功能的对象。

Example

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

我们为名为 proxyObj 的 person 对象定义了代理对象。此外,我们还将处理程序对象作为 Proxy() 构造函数参数传递。

在处理程序对象中,我们定义了访问对象属性的 getter。getter 检查对象是否包含您要查找的属性。如果是,它将返回属性值。否则,它将返回消息,说明对象不包含该属性。

<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 = {
         // Defining the 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。这里,我们自定义了对象的默认行为来返回一种简洁而可读的方法。

JavaScript Proxy Handlers

JavaScript 中有多个代理处理程序可用,我们将在下面涵盖其中一些内容。代理处理程序用于覆盖对象的默认行为。

The JavaScript get() proxy handler

JavaScript 中的 get() 代理处理程序允许您更改对象的属性访问行为。

按照以下语法使用代理对象上的 get() 代理处理程序。

get(target, property, receiver)
  1. target − 这是目标对象。

  2. property − 这是需要访问其值的对象。

  3. receiver − 这是代理对象本身。

在下面的代码中,watch 对象包含品牌、颜色和价格属性。我们已经为 watch 对象创建了代理。

处理程序对象包含 get() 处理程序,并且在没有该处理程序的情况下返回属性值。否则,它将返回一条可读消息。

<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.

The JavaScript set() proxy handler

JavaScript 中的 set() 代理处理程序用于更改更新对象属性的默认行为。

按照以下语法使用 set() 代理处理程序。

set(target, property, value, receiver)
  1. target − 这是目标对象。

  2. property − 这是用于改变其值的属性。

  3. value - 这是一个更新后的值。

  4. receiver − 这是代理对象本身。

在下边的代码中,处理程序对象包含 set() 代理处理程序。set() 处理程序检查属性是否等于“price”。如果为真,它将用新值更新属性值。否则,它将“不可用”设置为对象属性。

<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

The JavaScript apply() proxy handler

apply() 代理处理程序用于更改函数调用的默认行为。

按照下边的语法使用 apply() 代理处理程序。

apply(target, thisArg, arguments)
  1. target - 这是需要执行的目标函数。

  2. thisArg - 它指的是在函数主体中应使用 this 关键字访问其元素的上下文。

  3. arguments - 这是要传递给函数的参数数组。

在下边的代码中,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 `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

Uses of the Proxy Object in JavaScript

在这里,我们用示例说明了使用代理对象的好处。

For Validation

您可以在 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]) {
               // Validing the new value using the previous value
               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

For Access Control

您还可以使用代理处理程序控制 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

Side Effects

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

在下面的示例中,emailValidator() 函数检查电子邮件中是否包含 '@'。如果为真,它将返回 true。否则,它将返回 false。

在 set() 代理处理程序中,我们根据 emailValidator() 函数的返回值更新属性值。

<html>
<body>
   <p id = "output"> </p>
   <script>
      const emails = {
         email1: "abcd@gmail.com",
      }
      // Function to validate the 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

但是,代理处理程序的使用并不受限制,我们无法在本教程中涵盖每种用例。因此,您可以探索更多代理处理程序的用例。

JavaScript Proxy Handlers List

在这里,我们列出了 JavaScript 中的所有代理处理程序。

Proxy Handler Methods

Sr.No.

Proxy Handler

Description

1

apply()

它改变了函数调用的默认行为。

2

construct()

捕获新对象的构造。

3

defineProperty()

改变定义新属性的行为。

4

deleteProperty()

改变删除新属性的行为。

5

get()

改变访问对象属性的行为。

6

getOwnPropertyDescriptor()

捕获对象中 getOwnPropertyDescriptor() 方法。

7

getPrototypeOf()

Trapping the internal methods.

8

has()

操纵检查对象是否包含 property。

9

isExtensible()

捕获 Object 的 isExtensible() 方法。

10

ownKeys()

改变 ownKeys() 方法的行为。

11

preventExtension()

捕获阻止对象扩展。

12

set()

改变添加新 property 或更新对象中 property 值的默认行为。

13

setPrototypeOf()

定制 Object.setPrototypeOf() 方法。

Constructor

Sr.No.

Constructor

Description

1

Proxy()

它用于创建代理对象。

Static Method

Sr.No.

Method

Description

1

revocable()

它还用于创建与 Proxy() 构造函数类似的新代理对象。