One article to understand the various application scenarios of the Proxy class in JavaScript

83f93b2517c849206331e8ac33a903f5.png

Created by Midjourney, future developer

As the world becomes increasingly digitized, web applications are more ubiquitous than ever. As a result, developers are constantly looking for new tools and techniques to make their jobs easier. One of the tools that has gained significant popularity in recent years is the Proxy class in JavaScript.

At its core, the Proxy class is a powerful feature that allows developers to intercept and customize basic language operations. This makes it a very versatile tool that can be used in a variety of use cases. In this article, we'll take a deep dive into the Proxy class in JavaScript and explore one of its most useful use cases.

The Proxy class in JavaScript allows you to intercept and customize actions performed on objects. Here are some use cases of the Proxy class:

1. Verification

You can use the Proxy class to validate object properties before accessing or modifying them. This is useful in situations where you want to enforce certain rules on object properties, such as making sure they have a certain data type, or making sure they fall within a certain range.

Let me demonstrate:

const person = {
  name: 'John',  // 人的名字
  age: 30,  // 人的年龄
};

const validator = {
  set(target, key, value) {
    // 在设置属性值时,如果属性名称是'age',并且属性值不是数字类型,就抛出类型错误
    if (key === 'age' && typeof value !== 'number') {
      throw new TypeError('Age must be a number');
    }
    // 否则,将属性值设置到目标对象上
    target[key] = value;
    // 并返回true
    return true;
  },
};

// 创建一个代理对象,将目标对象和验证器对象传递给Proxy类的构造函数
const personProxy = new Proxy(person, validator);

// 尝试将age属性设置为字符串类型的'30',将抛出类型错误
personProxy.age = '30'; // 抛出类型错误:Age must be a number

Here, we create a person object and a validator object to check if the age property is a number. Then, we use the Proxy class to create a personProxy object, passing the person object and validator object to it. When we try to set the age property of the personProxy object to a non-numeric value, a TypeError will be thrown, preventing the property from being set.

2. Cache

You can use the Proxy class to cache object property values, which can improve performance by reducing the need to recompute values ​​that have already been calculated.

Let's look at an example:

// 一个耗时的计算函数,将生成随机数
const expensiveCalculation = () => {
  console.log('正在执行耗时计算...');
  return Math.random();
};

// 一个用于缓存计算结果的Map对象
const cache = new Map();

// 创建一个代理对象,使用Proxy类的apply()方法来拦截函数的调用
const calculationProxy = new Proxy(expensiveCalculation, {
  apply(target, thisArg, args) {
    // 将函数调用的参数作为缓存的键,用下划线连接起来
    const cacheKey = args.join('_');
    // 如果缓存中没有这个键,则执行计算函数并将结果存入缓存
    if (!cache.has(cacheKey)) {
      cache.set(cacheKey, target.apply(thisArg, args));
    }
    // 返回缓存中的值
    return cache.get(cacheKey);
  },
});

// 第一次调用计算函数时,会执行计算操作,并将结果存入缓存
console.log(calculationProxy()); // 输出 "正在执行耗时计算..." 和计算结果 0.5932315027880835

// 第二次调用计算函数时,不会执行计算操作,而是直接从缓存中取出结果
console.log(calculationProxy()); // 直接输出缓存中的结果 0.5932315027880835

In the sample code above, we define a time-consuming calculation function and a cache object to store the previously calculated results. We then created a calculationProxy object using the Proxy class, passing it the expensiveCalculation function and a new object containing an apply method that checks the cache before performing the calculation. When we call the calculationProxy function multiple times, the time-consuming calculation results are only calculated once, and then cached for use in subsequent calls, thereby significantly improving performance.

3. Logging

You can use the Proxy class to log object property access and modification events, which is useful for debugging or auditing purposes.

Let's implement an example:

const person = {
  name: 'John',  // 人的名字
  age: 30,  // 人的年龄
};

// 一个日志记录器对象,使用Proxy类的get()和set()方法来拦截对象属性的访问和修改
const logger = {
  get(target, key) {
    // 在获取属性值时,记录访问日志
    console.log(`访问了属性: ${key}`);
    return target[key];
  },
  set(target, key, value) {
    // 在设置属性值时,记录修改日志
    console.log(`修改了属性: ${key}`);
    target[key] = value;
    return true;
  },
};

// 创建一个代理对象,将目标对象和日志记录器对象传递给Proxy类的构造函数
const personProxy = new Proxy(person, logger);

// 访问age属性时,将记录访问日志
personProxy.age; // 输出 "访问了属性: age"

// 修改age属性时,将记录修改日志
personProxy.age = 40; // 输出 "修改了属性: age"

In the sample code above, we defined a person object and a logger object to log property access and modification events. Then, we created a personProxy object using the Proxy class, passing the person object and logger object to it. When we access or modify properties of the personProxy object, the logger will be invoked, causing log messages to be printed to the console.

4. Access control

You can use the Proxy class to implement access control of object properties. This is useful in situations where you want to restrict access to certain properties based on user permissions.

Let's take a look at its implementation:

const user = {
  name: 'John',  // 用户名
  email: '[email protected]',  // 用户邮箱
  isAdmin: false,  // 是否是管理员
};

// 一个访问控制器对象,使用Proxy类的get()方法来拦截对象属性的访问
const accessControl = {
  get(target, key) {
    // 如果用户不是管理员,且试图访问email属性,则抛出错误
    if (key === 'email' && !target.isAdmin) {
      throw new Error('拒绝访问');
    }
    // 否则,返回属性值
    return target[key];
  },
};

// 创建一个代理对象,将目标对象和访问控制器对象传递给Proxy类的构造函数
const userProxy = new Proxy(user, accessControl);

// 访问name属性时,将返回属性值
console.log(userProxy.name);  // 输出 "John"

// 访问email属性时,因为用户不是管理员,将抛出错误
console.log(userProxy.email);  // 抛出错误:"拒绝访问"

In the above sample code, we created a user (user) object, including the attributes name, email and isAdmin. Then, we created an access controller (accessControl) object, containing the get method, which is used to check whether the email property can be accessed according to the isAdmin property. Finally, we use the Proxy class to create a userProxy object, passing the user object and the accessControl object to it.

When we try to access the name property of the userProxy object, the get method of the access controller object will not be called, because the name property has no access restrictions. However, if we try to access the email property of the userProxy object, and the isAdmin property is false, an error will be thrown, preventing access to the email property.

5. Virtual attributes

You can use the Proxy class to create virtual properties, which are not actually stored on the object, but are computed dynamically when accessed. This is useful for situations where you want to expose additional properties on an object that are not the actual data model.

For example, we use Proxy to create a virtual property that calculates its area in real time based on the width and height properties of a rectangle object:

const rectangle = {
  width: 10,  // 矩形的宽度
  height: 20  // 矩形的高度
};

// 创建一个代理对象,将目标对象和一个拦截器对象传递给Proxy类的构造函数
const rectangleProxy = new Proxy(rectangle, {
  // 拦截器对象的get()方法,用于获取对象属性的值
  get: function(target, property) {
    // 如果请求获取的属性是"area",则返回计算出的面积值
    if (property === 'area') {
      return target.width * target.height;
    } else {
      // 否则,返回目标对象的对应属性值
      return target[property];
    }
  }
});

// 访问矩形对象的各个属性和虚拟属性area
console.log(rectangleProxy.width); // 输出 "10"
console.log(rectangleProxy.height); // 输出 "20"
console.log(rectangleProxy.area); // 输出 "200"

In this example, we define a get interceptor on the Proxy object to intercept access to the area property. When accessing the area property, the interceptor calculates the area based on the width and height properties of the original object and returns the result. For all other properties, the interceptor will forward access to the original object. In this way, we create a virtual property area, which is not actually stored on the object, but is dynamically calculated when it is accessed.

6. Packaging objects

You can use the Proxy class to add extra functionality to an object without modifying the original object. This is useful in situations where you want to extend the functionality of an object, but do not want to modify its behavior directly.

Let's create a small demo. We'll use Proxy to wrap extra functionality on the object to log every access to its properties:

const originalObject = {
  property1: 'value1',  // 原始对象的属性1
  property2: 'value2'   // 原始对象的属性2
};

// 创建一个代理对象,将原始对象和一个拦截器对象传递给Proxy类的构造函数
const loggingProxy = new Proxy(originalObject, {
  // 拦截器对象的get()方法,用于获取对象属性的值
  get: function(target, property) {
    console.log(`Getting property "${property}"`); // 记录访问的属性名
    return target[property];  // 返回原始对象对应属性的值
  },
  // 拦截器对象的set()方法,用于设置对象属性的值
  set: function(target, property, value) {
    console.log(`Setting property "${property}" to "${value}"`); // 记录设置的属性名和属性值
    target[property] = value;  // 设置原始对象对应属性的值
  }
});

// 访问代理对象的属性
loggingProxy.property1; // 输出 "Getting property "property1""
loggingProxy.property2 = 'new value'; // 输出 "Setting property "property2" to "new value""

As shown in the sample code above, we define get and set interceptors on the Proxy object to intercept access or modification of its properties. These interceptors log property names and values ​​to the console, and then forward access or modification to the original object. This way, we can add logging functionality to any object without directly modifying its behavior.

Finish

These are just one of many use cases for the Proxy class in JavaScript. The Proxy class is a powerful tool that can be used to implement various functions in JavaScript applications.

That’s all for today’s sharing, thank you for reading, I hope it can help you, it’s not easy to create articles, if you like my sharing, don’t forget to like and forward it, so that more people in need can see it, and finally don’t forget to pay attention "Front-end experts", your support will be the biggest motivation for me to share, and I will continue to output more content in the future, so stay tuned.

https://pandaquests.medium.com/use-cases-for-proxy-class-in-javascript-80f83f6ff3c0

Author: pandaquests

Indirect translation, some self-adapted and added parts, the translation level is limited, it is inevitable that there are omissions, welcome to correct

Guess you like

Origin blog.csdn.net/Ed7zgeE9X/article/details/129869765