Explore ES6 Proxy in detail, explore es6proxy

Source: Internet
Author: User
Tags hasownproperty

Explore ES6 Proxy in detail, explore es6proxy

Preface

In ES6, the Proxy constructor is an accessible global object. You can use it to collect information about request operations between objects and the actions of various operation objects, and return anything you want to do. Features such as Arrow functions, array deconstruct, and rest parameters in ES6 have been widely circulated once implemented. However, features such as Proxy are rarely used by developers, on the one hand, browser compatibility, on the other hand, developers need to have a deep understanding of the application scenarios to take advantage of these features. Personally, I like ES6 Proxy very much because it allows us to control external access to objects in a simple and easy-to-understand way. In the following section, I will first introduce how to use Proxy, and then list specific instances to explain the use cases of Proxy.

ProxyThe function is very similar to the proxy mode in the design mode. This mode is commonly used in three aspects:

1. and monitors external access to objects

2. complexity of functions or classes

3. Verify the operation or manage required resources before the operation

In a browser that supports Proxy, Proxy is a global object and can be directly used.Proxy(target, handler) Is a constructor,target Is the proxy object,handlderIs an object that declares various proxy operations, and finally returns a proxy object. External access through proxy objectstargetWhen the object property is passed throughhandlerFrom this process, proxy objects are similar to middleware ). What operations can Proxy intercept? The most common operations are get (read) and set (modify) object attributes. Click here for the complete list of intercepted operations. In addition, the Proxy object providesrevokeMethod to cancel all proxy operations at any time. Before we officially introduce Proxy, we recommend that you have a certain understanding of Reflect, which is also a new Global Object added to ES6.

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 target object to be proxytargetAnd then declarehandlerObject, and then useProxy(target, handler)Create proxy objectproxyAnd then allproxyPairtarget All access to the attribute will go through handler .

1. Extraction verification module

Let's start with a simple type verification. This example demonstrates how to use Proxy to ensure data type accuracy:

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) ;}}); // throw an error because "foo" is not a numeric value numericDataStore. count = "foo"; // The value is successfully assigned to numericDataStore. count = 333;

If you want to develop a checker directly for all the properties of the object, the code structure may quickly become bloated. Using Proxy, you can separate the checker from the core logic into one:

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); // The following operations will report an error. name = 0; bill. age = 'bill '; Bill. age = 15;

With the separation of the validator and the main logic, you can expand infinitelypersonValidatorsThe content of the validator, without directly damaging the related classes or functions. To be more complex, we can also use the Proxy to simulate the type check to check whether the function has received the correct parameters of the type and quantity:

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 3obj.pickyMethodTwo("wopdopadoo", {}); // > You are incorrectly implementing the signature of pickyMethodTwo. Check param 1// No warnings loggedobj.pickyMethodOne({}, "a little string", 123); obj.pickyMethodOne(123, {});

2. Private attributes

In JavaScript or other languages, you can easily add underscores before the variable name._ To indicate that this is a private property (not a real private property), but we cannot guarantee that no one will actually access or modify it. In the following code, we declare a privateapiKeyTo facilitateapi The internal method call of this object, but you do not want to access it from the externalapi._apiKey:

var api = {   _apiKey: '123abc456def',  /* mock methods that use this._apiKey */  getUsers: function(){},   getUser: function(userId){},   setUser: function(userId, config){}};// logs '123abc456def';console.log("An apiKey we want to keep private", api._apiKey);// get and mutate _apiKeys as desiredvar apiKey = api._apiKey; api._apiKey = '987654321';

Obviously, there is no constraint in conventions. With ES6 Proxy, we can implement real private variables. The following shows two different private variables for different reading methods.

The first method is to use set/get to intercept read/write requests and returnundefined:

Let api ={_ apiKey: '123abc456def ', getUsers: function () {}, getUser: function (userId) {}, setUser: function (userId, config ){}}; const RESTRICTED = ['_ apikey']; 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) ;}}); // The following operations will throw an error console. log (api. _ apiKey); api. _ apiKey = '000000 ';

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

var api = {   _apiKey: '123abc456def',  getUsers: function(){ },   getUser: function(userId){ },   setUser: function(userId, config){ }};const RESTRICTED = ['_apiKey'];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 _apiKeyconsole.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 logs

For attributes or interfaces that call frequently, run slowly, or consume a large amount of execution environment resources, developers want to record their usage or performance, in this case, you can use Proxy to act as the middleware and easily implement the log function:

let api = {   _apiKey: '123abc456def',  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. Warning and Interception

Suppose you don't want other developers to delete it.noDeleteAttribute, but also want to calloldMethodThe developer understands that this method has been abandoned, or tells the developer not to modify it.doNotChangeProperties, you can use Proxy to implement:

let dataStore = {   noDelete: 1235,  oldMethod: function() {/*...*/ },  doNotChange: "tried and true"};const NODELETE = ['noDelete']; const NOCHANGE = ['doNotChange'];const DEPRECATED = ['oldMethod']; 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 === 'function' ?      function(...args) {        Reflect.apply(target[key], target, args);      } :      val;  }});// these will throw errors or log warnings, respectivelydataStore.doNotChange = "foo"; delete dataStore.noDelete; dataStore.oldMethod();

5. Filter Operations

Some operations occupy a lot of resources, such as transferring large files. If the file is already being sent in multiple parts, you do not need to make a corresponding (non-absolute) response to the new request ), in this case, you can use the Proxy to perform Feature Detection on the request and filter out what does not need to be responded and what needs to be responded based on the features. The following code demonstrates how to filter features. It is not a complete code. I believe you will understand the highlights of this Code:

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 supports cancelingtargetIs usually used to completely close access to data or interfaces. In the following example, we useProxy.revocableMethod:

let sensitiveData = { username: 'devbryce' };const {sensitiveData, revokeAccess} = Proxy.revocable(sensitiveData, handler);function handleSuspectedHack(){   revokeAccess();}// logs 'devbryce'console.log(sensitiveData.username);handleSuspectedHack();// TypeError: Revokedconsole.log(sensitiveData.username);

Decorator

The Decorator implemented in ES7 is equivalent to the Decorator mode in the design mode. If the area is simpleProxyAndDecoratorThe core function of Proxy is to control external access to the agent. The core function of Decorator is to enhance the functions of the Decorator. As long as they are well differentiated in their core application scenarios, functions such as access logs can be implemented using the Decorator, although the Proxy is used in this article, developers can freely choose based on project requirements, Team specifications, and their preferences.

Summary

ES6 Proxy is very practical, seemingly simple, but very useful. I hope to help you learn ES6.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.