当前位置:网站首页>ES6 essence:

ES6 essence:

2020-11-06 01:17:00 :::::::

Introduction

This paper mainly introduces ES6 in Proxy and Reflect The essence of knowledge , And some examples are given .Proxy Agent means agent , Agents generated for objects through operations , Implement intercepting programming for various operations of objects .Reflect It's a more strict one 、 Sound operation object method module . because Proxy The method of agency and Reflect The methods included basically correspond to , And in the interception method should use the corresponding Reflect Method returns the result , So combine the two together to share .

1 Proxy

1.1 Ascend the hall

Think of a question first , How to control the reading and modification of a property of an object ( It doesn't involve closures creating private properties )? First create container properties that should not be changed directly :_ Property name , Then set the corresponding setter and getter Function or create the corresponding operation method .

---  Set up  setter  and  getter  function 
let obj = {
  _id: undefined,
  get id() {
    return this._id;
  },
  set id(v) {
    this._id = v;
  }
};
obj.id = 3; //  Quite a :obj._id = 3
console.log(obj.id); // console.log(obj._id);

---  Create access and modify methods 
let obj = {
  _id: undefined,
  id() {
    if (!arguments.length) return this._id;
    this._id = arguments[0];
  }
};
obj.id(3); //  Quite a :obj._id = 3
console.log(obj.id()); // console.log(obj._id);

There are obvious flaws in this : Repeat the settings for each attribute that needs to be controlled , And in fact, container properties can be arbitrarily modified . If an upgrade is required , We need to monitor to see 、 Delete 、 The operation of traversing the properties of an object , What do I do ?ES6 Before, it was only cold sauce ,ES6 after Proxy Do it for you .

let obj = { id: 0, name: 'Wmaker' };
let objProxy = new Proxy(obj, {
  get(target, attr) {
    console.log(`Get ${attr}`);
    return target[attr];
  },
  set(target, attr, val) {
    console.log(`Set ${attr}`);
    target[attr] = val;
    return true;
  }
});
objProxy.id; //  Print out :Get id, Quite a :obj.id;
objProxy.name; //  Print out :Get name, Quite a :obj.name;

1.2 Enter the room

As can be seen from the example in the previous section ,Proxy Is the constructor that generates the proxy . The first parameter passed in is the object to be proxy , The second parameter is the configuration object that needs to be intercepted ( After that, all interceptable operations, their meanings and considerations are listed ). Each interception operation in the configuration object , Both have default format input parameters , Some also require specific return values ( Here are some of the rules ).

The generated proxy is a proxy instance associated with the proxy object , It can be treated like a normal object . That is , Can be delete Drop an attribute , Can be traversed or prototyped . All actions on the agent , They all act directly on the surrogate object , You can also configure interception operations for them . The point of anger is , Mr. Cang can do well , How can our teacher Ozawa be poor ? What's more, it's not just objects that can be represented , Functions that belong to objects 、 Arrays are unconditionally accepted .

After generating a proxy for an object , You can still manipulate the original object , But of course this is not recommended .

Parameters Different interceptors have different input parameters , But it's usually the principal object , This operation requires parameters, etc. and proxy objects . You don't have to remember the parameters of each interceptor function , Reduce the burden on the brain , Print out when using arguments Check it out at a glance .

Return value In the interception method , Try to use Reflect The corresponding method is operated , And return the return value of the method . On the one hand, it's simple , What's more important is that in different ways or under certain circumstances , There are rigid requirements for return values , Otherwise, report the error directly . such as construct() An object must be returned , Otherwise, the report will be wrong . Another example set() In strict mode , Must return true Or it can be transformed into true Value , Whether the operation is successful or not .

"use strict";

---  Wrong way 
let obj = { id: 0 };
let objProxy = new Proxy(obj, {
  set(target, attr, val) {
    console.log(`Set ${attr}`);
    return target[attr] = val;
  }
});

objProxy.id = 1; //  Successful operation .
objProxy.id = 0; //  The operation has been successful , But wrong reporting , No further execution .

---  Recommended Practice 
let obj = { id: 0 };
let objProxy = new Proxy(obj, {
  set(target, attr, val) {
    console.log(`Set ${attr}`);
    return Reflect.set(target, attr, val);
  }
});

objProxy.id = 1; //  Successful operation .
objProxy.id = 0; //  Successful operation .

The return value of the interceptor method is not directly reflected to the outside ,JS There will be some validation and exclusion . For example, even in ownKeys() Return all the values in , But actually, only the corresponding series goes to the outside .

 The results of two printing are not equal .

let obj = { id: 0, [Symbol.iterator]() {} };
let objProxy = new Proxy(obj, {
  ownKeys(target) {
    let res = Reflect.ownKeys(target);
    console.log('1', res);
    return res;
  }
});

console.log( Object.keys('2', objProxy) );

Restrictive continuance When the surrogate object itself has some limitations , For example, it is not extensible or its properties are not writable and configurable . The operation of the object itself has been limited , In this case, if you execute the corresponding proxy operation , It's natural to report a mistake . For example, when an attribute is not writable , If the agent and execute set() operation , It will directly report an error .

let obj = { id: 0 };
Object.defineProperty(obj, 'name', {
  value: 'Wmaker'
});

let objProxy = new Proxy(obj, {
  set(target, attr, val) {
    return Reflect.set(target, attr, val);
  }
});

objProxy.id = 1; //  Successful operation .
objProxy.name = 'Limo'; //  Report errors .

this Some internal properties or methods of native objects , Only through the right this Ability to visit , So there's no agency . For example, date objects ,new Proxy(new Date(), {}).getDate(), Wrong presentation : This is not a Date object .

 There are also workarounds , For example, for the need to be right  this  You can do this .

let p = new Proxy(new Date(), {
  get(target, attr) {
    const v = Reflect.get(target, attr);
    return typeof v === 'function'
      ? v.bind(target)
      : v;
  }
});
p.getTime(); //  There is no mistake .

In the configuration object this Point directly to the configuration object , Not a delegate object or a proxy object . In the delegate object this, It can be divided into two parts: existing in method and existing in getter/setter Two of them . Both get this In different ways , We illustrate with examples .

---  Patients with a , No,  set  Intercept operation .
let obj = {
  get id() {
    console.log('o', this);
  },
  fn() {
    console.log('o', this);
  }
};

let objProxy = new Proxy(obj, {});

objProxy.id; //  Print out  objProxy .
objProxy.fn(); //  Print out  objProxy .


---  Example 2 , Yes  set  Intercept operation . Actually used  target[attr]  Get attribute value .
let obj = {
  get id() {
    console.log('o', this);
  },
  fn() {
    console.log('o', this);
  }
};

let objProxy = new Proxy(obj, {
  get(target, attr) {
    console.log('p', this);
    return target[attr];
  }
});

objProxy.id;
//  Print out the configuration object and  obj.
//  Because it's actually through the proxy object, that is  target  Access to the  id  It's worth it .

objProxy.fn();
//  Print out the configuration object and  objProxy.
//  The method can be transformed into  (objProxy.fn).call(objProxy).
//  Although the method is also through  target  Visited , But for the method , Environment variables are determined from the beginning .

The prototype is a proxy If the prototype of the object is a proxy , When the operation reaches the prototype , It's actually a proxy object that operates on the prototype . At this time , Its behavior is consistent with that of normal agents .

let obj = Object.create(new Proxy({}, {
  get(target, attr) {
    console.log('In proxy.');
    return Reflect.get(target, attr);
  }
}));

obj.name; //  Print out  In proxy. .
//  When the corresponding property cannot be found on the instance , It's on the prototype , And then they were intercepted .

1.3 Agent category

Here's just a list of key points , For details, please see manual ( Standards and behavior are changing ).

get Block the read operation of property , Including array values .

set Block the assignment of properties , Including array assignment . In strict mode , Must return to be converted to true Value . In strict mode , If the proxy object has some restrictions ( Properties are not writable, etc ), An error will be reported when the corresponding interception operation is executed .

apply Intercept function calls 、call and apply operation .

has Intercept to determine whether the object has a certain property . Only right in and Reflect.has() Effective method ,for in It belongs to the traversal series .

construct Intercept new command , An object must be returned .

deleteProperty Intercept delete Attribute operation . In strict mode , Must return to be converted to true Value . In strict mode , If the proxy object has some restrictions ( Properties are not writable, etc ), An error will be reported when the corresponding interception operation is executed .

defineProperty Intercept Object.defineProperty(), Don't intercept defineProperties. In strict mode , If the proxy object has some restrictions ( Properties are not configurable, etc ), An error will be reported when the corresponding interception operation is executed .

getOwnPropertyDescriptor Intercept Object.getOwnPropertyDescriptor(), Don't intercept getOwnPropertyDescriptors. Must return an object or undefined, That is to return the same return value as the original method , Otherwise, the report will be wrong .

getPrototypeOf Intercept to get the object prototype , Must return an object or null. If the object is not extensible , Must return the real prototype object . Direct access __proto__, All kinds of methods and so on will trigger interception .

setPrototypeOf Intercept Object.setPrototypeOf() Method .

isExtensible Intercept Object.isExtensible() operation . The return value must be the same as isExtensible Attributes are consistent , Otherwise, an error will be thrown .

preventExtensions Intercept Object.preventExtensions(), The return value is automatically converted to a Boolean value .

ownKeys Intercept the traversal operation of the object's own properties . such as keys(),getOwnPropertyNames(),getOwnPropertySymbols() wait . The return value must be an array , Items can only be strings or Symbol, Otherwise, the report will be wrong . The return value is filtered according to the requirements of the calling method , such as Object.keys() There won't be symbole. If the target object itself contains non configurable properties , The property must be returned , Otherwise, the report will be wrong . If the target object is not extensible , The return value must contain all properties of the original object , And can't contain extra properties , Otherwise, the report will be wrong .

1.4 Proxy.revocable

This static method is also used to generate , But it also returns a method to recycle the agent . Use scenarios : Direct access to the target object is not allowed , Must be accessed through a proxy . And once the visit is over , Take back the agency , Not allowed to visit again .

let {proxy, revoke} = Proxy.revocable(obj, {});
revoke();
 In this case, its internal attribute value  [[IsRevoked]]  by  true, The agent can no longer be manipulated , Otherwise, the report will be wrong .

2 Reflect

2.1 effect

The ultimate goal is to be the host object of the internal methods of the language . for instance defineProperty, getPrototypeOf, preventExtensions It's obviously internal , It should not be hung on Object Next .

Provides the corresponding function to replace the imperative operation . Use Reflect.has(obj, attr) replace in operation . Use Reflect.deleteProperty(obj, attr) replace delete operation .

Make the behavior of function more perfect and strict . When properties cannot be defined ,Reflect.defineProperty return false Instead of throwing errors . When a parameter of type object is required to be non object , It will report an error directly instead of calling Object() To convert .

And Porxy Interceptable methods correspond to , Convenient when implementing custom behavior , Call directly to complete the default behavior .

2.2 Static methods

Here's just a list of key points , For details, please see manual .

Reflect.get Reflect.get(obj, attr, receiver) Return property value , No return undefined. receiver It's settings getter and setter Inside this Point to , The default point to obj.

Reflect.set Reflect.set(obj, attr, value, receiver) Setting property values , Returns a Boolean value . Be careful : When the attribute is not getter when , Pass in receiver Equivalent to setting receiver Property values on the object .

Reflect.has Reflect.has(obj, attr) equivalent attr in obj.

Reflect.deleteProperty Reflect.deleteProperty(obj, attr) equivalent delete obj[attr].

Reflect.construct Reflect.construct(func, args) args Equivalent to the use of apply The parameter array passed in by the method . Provides no use of new To call the constructor method , equivalent new func(...args).

Reflect.getPrototypeOf Function and parameter are equivalent Object.getPrototypeOf(obj).

Reflect.setPrototypeOf Function and parameter are equivalent Object.setPrototypeOf(obj, newProto).

Reflect.apply Function and parameter are equivalent Function.prototype.apply.call(func, thisArg, args).

Reflect.defineProperty Function and parameter are equivalent Object.defineProperty(obj, attr, descriptor).

Reflect.getOwnPropertyDescriptor Function and parameter are equivalent Object.getOwnPropertyDescriptor(obj, attr).

Reflect.isExtensible Reflect.isExtensible(obj) Returns a Boolean value , Indicates whether the current object is extensible .

Reflect.preventExtensions Reflect.preventExtensions(obj) Set the object to be non extensible , Returns a Boolean value .

Reflect.ownKeys Reflect.ownKeys(obj) Returns all properties of the object itself . Equate to Object.getOwnPropertyNames And Object.getOwnPropertySymbols The sum of the .

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[:::::::]所创,转载请带上原文链接,感谢