The arrow in the

ES6 array function, deconstruction, rest parameter characteristics by the widely circulated, but like Proxy properties are rarely seen developers in use, on the one hand is the browser compatibility, on the other hand is to play the advantage of these features to developers in-depth understanding of the use of the scene. Personally, I really like ES6's Proxy, because it allows us to control access to objects outside in a simple and easy way. In the following, I will first introduce the use of Proxy, and then enumerate a specific example to explain the use of Proxy.

Proxy, who see know, its function is very similar to the proxy mode in the design mode, this mode is used in three aspects: the object of the

  1. interception and monitoring of external access to reduce the complexity of function or class
  2. in complex operation before the operation in check or required

resource management support Proxy browser environment, Proxy is a global object that can be used directly. Proxy (target, handler) is a constructor. Target is the object of the proxy. Handlder is the object that declares all kinds of agent operation, and finally returns to a proxy object. Every time the external objects access the properties of the target object through the proxy object, they will pass through the handler object. From this process, the proxy object is very similar to middleware (Middleware). So what can Proxy intercept? The most common operations are get (read), set (modify) object attribute and so on. It can intercept operation list completely. Please click here. In addition, the Proxy object provides a revoke method that can log all the agent operations at any time. Before we formally introduce Proxy, we suggest that you have a certain understanding of Reflect. It is also a new global object of ES6. Please refer to MDN Reflect" in detail.


 const target name:'Billy = {Bob', age:} const {handler = 15; 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);; / / => "GET request made for name at Thu Jul 212016 15:26:20 GMT+0800 (CST)" / / => "Billy Bob" 

in the code above, we first define a proxy object target, then the statement contains all agency operations the handler object, then use the Proxy (target, handler) to create a proxy object proxy, then use proxy to access all of the properties of target are processed by handler.


out of check module let us start with a simple type checking start, this example demonstrates how to use Proxy to ensure data accuracy type:

 let {numericDataStore = count: 0, amount: 1234, total: 14}; numericDataStore Proxy = new (numericDataStore, target, key ({set, value if (typeof, proxy) {value! = ='number') {throw ("Error Properties in numericDataStore can only be numbers");} return Reflect.set (target, key, value, proxy);}}); / / an error, because "foo" is not a numerical numericDataStore.count = "foo"; / / assignment numericDataStore.count 

= 333; if you want to direct all attributes of the object of developing a checker may soon let generation Code structure becomes bloated, using Proxy can be separated from the core logic checker is 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 typeof VAL) {return}, = = ='string'; age (VAL) typeof age'number' &am {return = = = P; & age > class Person 18;}} {constructor (name, age) { = name; this.age = age; return createValidator (this, personValidators);}} = const bill new Person ('Bill', 25); / / the following are error = 0; bill.age ='Bill'; bill.age = 15; 

by separating calibrator and the main logic, you can extend personValidators validator content, but not for the class or function related directly damage. A bit more complicated, we can also use Proxy to simulate type checking, check whether the function receives the parameter type and number are correct:

 let obj {pickyMethodOne: = function (obj, STR, Num) {/ *... * /}, pickyMethodTwo: function (Num, obj) {/ *... * /}}; const argTypes = {pickyMethodOne: ["object", "string", "number"], pickyMethodTwo: ["number", "object"]}; obj new = Proxy (obj, function {get: (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 warnings logged obj.pickyMethodOne / / No ("a little string" {}, 123); obj.pickyMethodOne (123, {} 2.); 

in JavaScript or other languages, you will underline the Convention _ in front of the variable names to indicate that this is a private property (not really private), but we cannot guarantee that really no one to access or modify it. In the code below, we declare a private apiKey, easy call method API this object, but also do not want from external access to the api._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 desired var apiKey = api._apiKey; api._apiKey ='987654321'; 

clearly, there is no binding convention. Using ES6 Proxy, we can implement real private variables, and demonstrate two different privatization methods for different reads. The first method is to use set / get to intercept the read and write requests and return to the undefined:

 let API = {_apiKey:'123abc456def', getUsers: function (getUser: function) {}, {setUser:} (userId), 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 As will be thrown out the error console.log (api._apiKey); api._apiKey ='987654321'; 

second method is to use has in

 var intercept operation: API = {_apiKey:'123abc456def', getUsers: function (getUser: function) {}, {setUser:} (userId), function (userId, config) {}}; const = RESTRICTED ['_apiKey']; API = new (API, Proxy {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" (for API); VAR key in API (api.hasOwnProperty) {if (key) & & key = _apiKey) {console.log ("This will never be logged because the proxy obscures _apiKey...")}} 


access log

for those who call frequently, run slowly or occupy the property or interface execution environment more resources, developers will want to record the use or performance of them, this time you can use the Proxy as a middleware implementation of log color, an easy job to do function:

 let API ='123abc456def'function ({_apiKey:, getUsers:) {/ *... * /}, getUser: function (userId) {/ *... * /}, setUser: function (userId, config) {/ *... * /}}; function logMethodAsync (timestamp, method) {setTimeout (function () {console.log (`${timestamp} - Logging ${method} request asynchronously.`);}}, 0) = new API Proxy (API, function {get: (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 intercept

if you do not want to let other developers to delete the noDelete attribute, also want to let the developers know to call oldMethod this approach has been abandoned, or tell the developers do not modify the doNotChange attribute, then you can use the Proxy to achieve

 let: dataStore {noDelete: = 1235, oldMethod: (function) {/*... * /}, doNotChange: "tried and true"}; const NODELETE = ['noDelete']; const NOCHANGE const = ['doNotChange']; DEPRECATED = ['oldMethod']; dataStore = new (dataStore, Proxy {set (target, key, value, proxy {if (NOC) HANGE.includes (key) throw Error (`Error) {is} ${key}! 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 (T);}.

This concludes the body part