search
HomeWeb Front-endJS TutorialInstructions for using Proxy in ES6
Instructions for using Proxy in ES6Jun 13, 2018 am 10:57 AM
es6proxy

This article mainly introduces the usage scenarios of ES6 Proxy. Now I will share it with you and give you a reference.

Features such as arrow functions, array destructuring, and rest parameters in ES6 have been widely circulated as soon as they were implemented. However, features like Proxy are rarely used by developers. On the one hand, it is due to browser compatibility. On the other hand, in order to take advantage of these features, developers need to deeply understand their usage scenarios. Personally, I like ES6's Proxy very much because it allows us to control external access to objects in a concise and easy-to-understand way. In the following, I will first introduce how to use Proxy, and then explain the usage scenarios of Proxy by citing specific examples.

Proxy, as the name implies, its function is very similar to the proxy mode in the design pattern. This mode is often used in three aspects:

  1. Interception and monitoring of external requests Object access

  2. Reduce the complexity of functions or classes

  3. Verify operations or manage required resources before complex operations

In a browser environment that supports Proxy, Proxy is a global object and can be used directly. Proxy(target, handler) is a constructor, target is the object being proxied, handler is an object that declares various proxy operations, and ultimately returns a proxy object. Every time the outside world accesses the properties of the target object through the proxy object, it will pass through the handler object. From this process, the proxy object is very similar to middleware. So what operations can Proxy intercept? The most common operations are get (read), set (modify) object attributes and other operations. For a complete list of interceptable operations, please click here. In addition, the Proxy object also provides a revoke method to log out all proxy operations at any time. Before we formally introduce Proxy, it is recommended that you have a certain understanding of Reflect. It is also a new global object in ES6. For detailed information, please refer to MDN Reflect.

Basic

const target = { 
  name: 'Billy Bob',
  age: 15
};

const handler = { 
  get(target, key, proxy) {
    const today = new Date();
    console.log(`GET request made for ${key} at ${today}`);

    return Reflect.get(target, key, proxy);
  }
};

const proxy = new Proxy(target, handler);
proxy.name;
// => "GET request made for name at Thu Jul 21 2016 15:26:20 GMT+0800 (CST)"
// => "Billy Bob"

In the above code, we first define a proxy target object target, then declare the handler object that contains all proxy operations, and then use Proxy(target, handler) creates a proxy object proxy. After that, all accesses to the target attribute using proxy will be processed by the handler.

1. Extract verification module

Let us start with a simple type verification. This example demonstrates how to use Proxy to ensure the accuracy of data types. Characteristics:

let numericDataStore = { 
  count: 0,
  amount: 1234,
  total: 14
};

numericDataStore = new Proxy(numericDataStore, { 
  set(target, key, value, proxy) {
    if (typeof value !== 'number') {
      throw Error("Properties in numericDataStore can only be numbers");
    }
    return Reflect.set(target, key, value, proxy);
  }
});

// 抛出错误,因为 "foo" 不是数值
numericDataStore.count = "foo";

// 赋值成功
numericDataStore.count = 333;

If you want to directly develop a validator for all properties of an object, the code structure may quickly become bloated. Using Proxy, you can separate the validator from the core logic and make it self-contained. :

function createValidator(target, validator) { 
  return new Proxy(target, {
    _validator: validator,
    set(target, key, value, proxy) {
      if (target.hasOwnProperty(key)) {
        let validator = this._validator[key];
        if (!!validator(value)) {
          return Reflect.set(target, key, value, proxy);
        } else {
          throw Error(`Cannot set ${key} to ${value}. Invalid.`);
        }
      } else {
        throw Error(`${key} is not a valid property`)
      }
    }
  });
}

const personValidators = { 
  name(val) {
    return typeof val === 'string';
  },
  age(val) {
    return typeof age === 'number' && age > 18;
  }
}
class Person { 
  constructor(name, age) {
    this.name = name;
    this.age = age;
    return createValidator(this, personValidators);
  }
}

const bill = new Person('Bill', 25);

// 以下操作都会报错
bill.name = 0; 
bill.age = 'Bill'; 
bill.age = 15;

By separating the validator and the main logic, you can infinitely expand the content of the personValidators validator without causing direct damage to related classes or functions. To make it more complicated, we can also use Proxy to simulate type checking and check whether the function receives the correct type and number of parameters:

let obj = { 
  pickyMethodOne: function(obj, str, num) { /* ... */ },
  pickyMethodTwo: function(num, obj) { /*... */ }
};

const argTypes = { 
  pickyMethodOne: ["object", "string", "number"],
  pickyMethodTwo: ["number", "object"]
};

obj = new Proxy(obj, { 
  get: function(target, key, proxy) {
    var value = target[key];
    return function(...args) {
      var checkArgs = argChecker(key, args, argTypes[key]);
      return Reflect.apply(value, target, args);
    };
  }
});

function argChecker(name, args, checkers) { 
  for (var idx = 0; idx < args.length; idx++) {
    var arg = args[idx];
    var type = checkers[idx];
    if (!arg || typeof arg !== type) {
      console.warn(`You are incorrectly implementing the signature of ${name}. Check param ${idx + 1}`);
    }
  }
}

obj.pickyMethodOne(); 
// > You are incorrectly implementing the signature of pickyMethodOne. Check param 1
// > You are incorrectly implementing the signature of pickyMethodOne. Check param 2
// > You are incorrectly implementing the signature of pickyMethodOne. Check param 3

obj.pickyMethodTwo("wopdopadoo", {}); 
// > You are incorrectly implementing the signature of pickyMethodTwo. Check param 1

// No warnings logged
obj.pickyMethodOne({}, "a little string", 123); 
obj.pickyMethodOne(123, {});

2. Private properties

In In JavaScript or other languages, it is a common practice to add an underscore _ before a variable name to indicate that it is a private property (not really private), but we cannot guarantee that no one will access or modify it. In the following code, we declare a private apiKey to facilitate method calls within the api object, but we do not want to be able to access the api from the outside._apiKey:

var api = { 
  _apiKey: &#39;123abc456def&#39;,
  /* mock methods that use this._apiKey */
  getUsers: function(){}, 
  getUser: function(userId){}, 
  setUser: function(userId, config){}
};

// logs &#39;123abc456def&#39;;
console.log("An apiKey we want to keep private", api._apiKey);

// get and mutate _apiKeys as desired
var apiKey = api._apiKey; 
api._apiKey = &#39;987654321&#39;;

Obviously, the convention is not binding of. Using ES6 Proxy we can implement real private variables. The following demonstrates two different privatization methods for different reading methods. The first method is to use set/get to intercept read and write requests and return undefined:

let api = { 
  _apiKey: &#39;123abc456def&#39;,
  getUsers: function(){ }, 
  getUser: function(userId){ }, 
  setUser: function(userId, config){ }
};

const RESTRICTED = [&#39;_apiKey&#39;];
api = new Proxy(api, { 
  get(target, key, proxy) {
    if(RESTRICTED.indexOf(key) > -1) {
      throw Error(`${key} is restricted. Please see api documentation for further info.`);
    }
    return Reflect.get(target, key, proxy);
  },
  set(target, key, value, proxy) {
    if(RESTRICTED.indexOf(key) > -1) {
      throw Error(`${key} is restricted. Please see api documentation for further info.`);
    }
    return Reflect.get(target, key, value, proxy);
  }
});

// 以下操作都会抛出错误
console.log(api._apiKey);
api._apiKey = &#39;987654321&#39;;

The second method is to use has to intercept in operations:

var api = { 
  _apiKey: &#39;123abc456def&#39;,
  getUsers: function(){ }, 
  getUser: function(userId){ }, 
  setUser: function(userId, config){ }
};

const RESTRICTED = [&#39;_apiKey&#39;];
api = new Proxy(api, { 
  has(target, key) {
    return (RESTRICTED.indexOf(key) > -1) ?
      false :
      Reflect.has(target, key);
  }
});

// these log false, and `for in` iterators will ignore _apiKey
console.log("_apiKey" in api);

for (var key in api) { 
  if (api.hasOwnProperty(key) && key === "_apiKey") {
    console.log("This will never be logged because the proxy obscures _apiKey...")
  }
}

3. Access log

For those properties or interfaces that are called frequently, run slowly, or occupy a lot of execution environment resources, developers will want to record their usage or performance. At this time, Proxy can be used to act as middleware. Role, it is easy to implement the logging function:

let api = { 
  _apiKey: &#39;123abc456def&#39;,
  getUsers: function() { /* ... */ },
  getUser: function(userId) { /* ... */ },
  setUser: function(userId, config) { /* ... */ }
};

function logMethodAsync(timestamp, method) { 
  setTimeout(function() {
    console.log(`${timestamp} - Logging ${method} request asynchronously.`);
  }, 0)
}

api = new Proxy(api, { 
  get: function(target, key, proxy) {
    var value = target[key];
    return function(...arguments) {
      logMethodAsync(new Date(), key);
      return Reflect.apply(value, target, arguments);
    };
  }
});

api.getUsers();

4. Early warning and interception

Suppose you don’t want other developers to delete the noDelete attribute, and you also want developers to call oldMethod After learning that this method has been abandoned, or telling the developer not to modify the doNotChange attribute, you can use Proxy to implement it:

let dataStore = { 
  noDelete: 1235,
  oldMethod: function() {/*...*/ },
  doNotChange: "tried and true"
};

const NODELETE = [&#39;noDelete&#39;]; 
const NOCHANGE = [&#39;doNotChange&#39;];
const DEPRECATED = [&#39;oldMethod&#39;]; 

dataStore = new Proxy(dataStore, { 
  set(target, key, value, proxy) {
    if (NOCHANGE.includes(key)) {
      throw Error(`Error! ${key} is immutable.`);
    }
    return Reflect.set(target, key, value, proxy);
  },
  deleteProperty(target, key) {
    if (NODELETE.includes(key)) {
      throw Error(`Error! ${key} cannot be deleted.`);
    }
    return Reflect.deleteProperty(target, key);

  },
  get(target, key, proxy) {
    if (DEPRECATED.includes(key)) {
      console.warn(`Warning! ${key} is deprecated.`);
    }
    var val = target[key];

    return typeof val === &#39;function&#39; ?
      function(...args) {
        Reflect.apply(target[key], target, args);
      } :
      val;
  }
});

// these will throw errors or log warnings, respectively
dataStore.doNotChange = "foo"; 
delete dataStore.noDelete; 
dataStore.oldMethod();

5. Filtering operation

Someone Some operations will occupy a lot of resources, such as transferring large files. At this time, if the file is already being sent in chunks, there is no need to respond to new requests (not absolute). At this time, you can use Proxy to perform feature detection on the current request. , and filter out which ones do not require response and which ones do need to respond based on the characteristics. The following code simply demonstrates the method of filtering features. It is not a complete code. I believe everyone will understand the beauty of it:

let obj = { 
  getGiantFile: function(fileId) {/*...*/ }
};

obj = new Proxy(obj, { 
  get(target, key, proxy) {
    return function(...args) {
      const id = args[0];
      let isEnroute = checkEnroute(id);
      let isDownloading = checkStatus(id);   
      let cached = getCached(id);

      if (isEnroute || isDownloading) {
        return false;
      }
      if (cached) {
        return cached;
      }
      return Reflect.apply(target[key], target, args);
    }
  }
});

6. Interrupt proxy

Proxy support Cancel the proxy for the target at any time. This operation is often used to completely close access to data or interfaces. In the following example, we use the Proxy.revocable method to create a proxy object for a revocable proxy:

let sensitiveData = { username: &#39;devbryce&#39; };
const {sensitiveData, revokeAccess} = Proxy.revocable(sensitiveData, handler);
function handleSuspectedHack(){ 
  revokeAccess();
}

// logs &#39;devbryce&#39;
console.log(sensitiveData.username);
handleSuspectedHack();
// TypeError: Revoked
console.log(sensitiveData.username);

Decorator

The Decorator implemented in ES7 is equivalent to the decorator pattern in the design pattern. If we simply distinguish the usage scenarios of Proxy and Decorator, it can be summarized as follows: The core function of Proxy is to control the external access to the interior of the proxy, and the core function of Decorator is to enhance the function of the decorator. As long as their core usage scenarios are distinguished, functions such as access logs, although this article uses Proxy to implement them, can also be implemented using Decorator. Developers can implement them based on project needs, team specifications, and their own preferences. Freedom of choice.

The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.

Related articles:

How to introduce public css files through vue

What are the methods of using ajax in Vue?

How to implement data distribution slot in vue.js

The above is the detailed content of Instructions for using Proxy in ES6. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
es6怎么判断是否为数组es6怎么判断是否为数组Apr 25, 2022 pm 06:43 PM

在es6中,可以利用“Array.isArray()”方法判断对象是否为数组,若判断的对象是数组,返回的结果是true,若判断对象不是数组,返回的结果是false,语法为“Array.isArray(需要检测的js对象)”。

es6中遍历跟迭代的区别是什么es6中遍历跟迭代的区别是什么Apr 26, 2022 pm 02:57 PM

es6中遍历跟迭代的区别是:遍历强调的是要把整个数据依次全部取出来,是访问数据结构的所有元素;而迭代虽然也是依次取出数据,但是并不保证取多少,也不保证把所有的数据取完,是遍历的一种形式。

es6中怎么判断两个对象是否相等es6中怎么判断两个对象是否相等Apr 19, 2022 pm 03:34 PM

在es6中,可用Object对象的is()方法来判断两个对象是否相等,该方法检测两个变量的值是否为同一个值,判断两个对象的引用地址是否一致,语法“Object.is(对象1,对象2)”;该方法会返回布尔值,若返回true则表示两个对象相等。

es6怎么将数字转为字符串es6怎么将数字转为字符串Apr 19, 2022 pm 06:38 PM

转换方法:1、利用“+”给数字拼接一个空字符,语法“数字+""”;2、使用String(),可把对象的值转换为字符串,语法“String(数字对象)”;3、用toString(),可返回数字的字符串表示,语法“数字.toString()”。

sort排序是es6中的吗sort排序是es6中的吗Apr 25, 2022 pm 03:30 PM

sort排序是es6中的;sort排序是es6中用于对数组的元素进行排序的方法,该方法默认不传参,按照字符编码顺序进行排序,排序顺序可以是字母或数字,并按升序或降序,语法为“array.sort(callback(a,b))”。

es6中assign的用法是什么es6中assign的用法是什么May 05, 2022 pm 02:25 PM

在es6中,assign用于对象的合并,可以将源对象的所有可枚举属性复制到目标对象;若目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性,语法为“Object.assign(...)”

es6怎么改变数组数据es6怎么改变数组数据Apr 26, 2022 am 10:08 AM

改变方法:1、利用splice()方法修改,该方法可以直接修改原数组的内容,语法为“数组.splice(开始位置,修改个数,修改后的值)”;2、利用下标访问数组元素,并重新赋值来修改数组数据,语法为“数组[下标值]=修改后的值;”。

import as在es6中的用法是什么import as在es6中的用法是什么Apr 25, 2022 pm 05:19 PM

在es6中,import as用于将若干export导出的内容组合成一个对象返回;ES6的模块化分为导出与导入两个模块,该方法能够将所有的导出内容包裹到指定对象中,语法为“import * as 对象 from ...”。

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),