Proxy and Reflect are new apis for ES6.

Reflect

Reflect is a built-in object that provides methods to intercept JavaScript operations. Reflect is not a function object, so it is not constructible. All of Reflect’s methods are static just like Math, it doesn’t have static properties yet.

The Reflect object has the same method as the Proxy object.

Reflect has 13 static methods:

It can be broken down into a part of the method that originally existed on Object, which has been escaped to Reflect and changed slightly to make the method more reasonable.

  1. defineProperty 与Object.definePropertySimilar, but when the object cannot be definedObject.definePropertyComplains andReflect.definePropertyNo, it will returnfalseReturns on successtrueIf it is not an object, an error will be reported.
  2. getPrototypeOf(target)Object.getPrototypeOfReturns the prototype of the specified object.
  3. setPrototypeOf(target, prototype)Object.setPrototypeOfAgain, it sets the stereotype of the specified object to another object.
  4. getOwnPropertyDescriptor()Object.getOwnPropertyDescriptorAs such, returns the value of the given property if it exists in the objectAttribute descriptor.
  5. isExtensible(target)Object.isExtensibleSimilarly, to determine whether an object is extensible (whether new attributes can be added to it), the difference is that when the parameters are not objects (original values),ObjectTo force it into an object,ReflectError is reported directly.
  6. preventExtensions(target)Object.preventExtensionsSimilarly, prevent new attributes from being added to the object, the difference being the same as before.
  7. apply(func, thisArg, args)Function.prototype.apply.call(fn, obj, args)The same.
  8. ownKeys(target)Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))As such, an array containing all its own attributes (excluding inherited attributes) is returned

The other part is to convert the functionality of the original operator into functional behavior.

  1. has(target, key)inOperator, which makes judgment operations function behavior.
  2. deleteProperty(target, key)deleteMakes the delete operation function behavior, returning a Boolean value representing success or failure.
  3. construct(target, argumentsList[, newTarget])newSame as the operator,targetConstructor. The second argument is the constructor argument class array. The third argument isnew.targetThe value of the.
  4. get(target, key[, receiver])obj[key]Again, the third argument is what to valuekeydeployedgetterTo access its functionthisThe binding ofreceiverObject.
  5. set(target, key, value[, receiver])Set up thetargetThe object’skeyAttribute is equal to thevalue, and the third argumentsetThe same. Returns a Boolean value.
/ / the old way
'assign' in Object // true

/ / a new way
Reflect.has(Object.'assign') // true

/ / the old way
Function.prototype.apply.call(Math.floor, undefined[1.75]) / / 1

/ / a new way
Reflect.apply(Math.floor, undefined[1.75]) / / 1

/ / the old way
delete myObj.foo;

/ / a new way
Reflect.deleteProperty(myObj, 'foo');

// New
const instance = new Greeting('Joe');

// Reflect. Construct
const instance = Reflect.construct(Greeting, ['Joe']);

/ / the old way
Object.defineProperty(MyDate, 'now', {
  value: () = > Date.now()
});

/ / a new way
Reflect.defineProperty(MyDate, 'now', {
  value: () = > Date.now()
});

Reflect.get(1.'foo') / / an error
Reflect.get(false.'foo') / / an error
Reflect.set(1.'foo', {}) / / an error
Reflect.set(false.'foo', {}) / / an error

// ---------------

var myObject = {
  foo: 1.bar: 2.get baz() {
    return this.foo + this.bar; }};var myReceiverObject = {
  foo: 4.bar: 4};Reflect.get(myObject, 'baz', myReceiverObject) / / 8
Copy the code

Proxy

Proxy objects are used to define the custom behavior of basic operations (such as property lookup, assignment, enumeration, function call, etc.), which is equivalent to making changes at the language level. Therefore, Proxy objects are a kind of “meta programming”, that is, programming a programming language.

A Proxy is like a Proxy between target objects, and any operation on the target goes through the Proxy. The agent can filter and overwrite external operations.

Proxy is a constructor that takes two parameters, target and handler,

A target is a target object wrapped in a Proxy (it can be any type of object, including a native array, a function, or even another Proxy).

Handler is an object whose properties are functions that define the behavior of the agent when an operation is performed.

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}! `);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}! `);
    return Reflect.set(target, key, value, receiver); }}); obj.count =1
// setting count!
++obj.count
// getting count!
// setting count!
//  2
Copy the code

Proxy has only one static method, Revocable (Target, handler), that can be used to create an undoable Proxy object. The two arguments are the same as those of the constructor. It returns an object containing the generated proxy object itself and the proxy object’s undo method.

Once a proxy object is destroyed, it becomes almost completely unavailable, and any proscriptable operations performed on it will raise TypeError (note that there are 14 proscriptable operations, and operations performed other than these 14 will not raise an exception). Once destroyed, the proxy object can never be restored to its original state, and its associated target and handler objects may be garbage collected. Calling the undo method more than once has no effect and, of course, no error.

var revocable = Proxy.revocable({}, {
  get(target, name) {
    return "The [[" + name + "]]"; }});// revocable -> {"proxy": proxy, "revoke": revoke}

var proxy = revocable.proxy;
proxy.foo;              // "[[foo]]"

revocable.revoke();     // Execute the undo method

proxy.foo;              // TypeError
proxy.foo = 1           / / the same TypeError
delete proxy.foo;       / / or TypeError
typeof proxy            // "object", because typeof is not a proxy operation
Copy the code

The Handler argument is a proxy function object that supports a total of 13 interceptor functions. Same as Reflect. If no action is defined, the action is forwarded to the target object.

const proxy = new Proxy({}, {
  get: function(target, property, receiver) {
    return receiver;
    // Receiver always points to the object where the original read operation is located, which is usually a Proxy instance.}}); proxy.getReceiver === proxy// true
Copy the code

If a property cannot be configured and writable, the Proxy cannot modify the property. Otherwise, an error will be reported when accessing the property through the Proxy object.

const target = Object.defineProperties({}, {
  foo: {
    value: 123.writable: false.configurable: false}});const handler = {
  get(target, propKey) {
    return 'abc'; }};const proxy = new Proxy(target, handler);

proxy.foo
// TypeError: Invariant check failed
Copy the code

The Apply method intercepts function calls, calls, and apply operations.

var target = function () { return 'I am the target'; };
var handler = {
  apply: function () {
    return 'I am the proxy'; }};var p = new Proxy(target, handler);

p()
// "I am the proxy"
Copy the code

The defineProperty method intercepts the Object.defineProperty operation.

var handler = {
  defineProperty (target, key, descriptor) {
    return false; }};var target = {};
var proxy = new Proxy(target, handler);
proxy.foo = 'bar' // Does not take effect
The // defineProperty method returns false, so adding new attributes is always invalid.
Copy the code

Note that defineProperty cannot add attributes that do not exist on the target object if the target object is non-extensible, or an error is reported. In addition, if a property of the target object is not writable or configurable, the defineProperty method cannot change the two Settings.

The getPrototypeOf method is used to intercept and retrieve object prototypes, and does the following:

  1. Object.prototype.__proto__
  2. Object.prototype.isPrototypeOf()
  3. Object.getPrototypeOf()
  4. Reflect.getPrototypeOf()
  5. instanceof

The ownKeys method, which intercepts the read of an object’s own properties, intercepts the following operations:

  1. Object.getOwnPropertyNames()
  2. Object.getOwnPropertySymbols()
  3. Object.keys()
  4. for... in

With a proxy, you can easily validate a value passed to an object.

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid'); }}// The default behavior to store the valueobj[prop] = value; }};let person = new Proxy({}, validator);

person.age = 100;

console.log(person.age); 
/ / 100

person.age = 'young'; 
// Throw an exception: Uncaught TypeError: The age is not an INTEGER

person.age = 300; 
// Throw an exception: Uncaught RangeError: The age seems invalid
Copy the code

This points to the

Although Proxy can Proxy the access of the target object, it is not a transparent Proxy of the target object, that is, without any interception, it cannot guarantee the consistency with the behavior of the target object. The main reason is that in the case of Proxy, the this keyword inside the target object points to Proxy.

const target = {
  m: function () {
    console.log(this=== proxy); }};const handler = {};

const proxy = new Proxy(target, handler);

target.m() // false
proxy.m()  // true
Copy the code
const target = new Date(a);const handler = {};
const proxy = new Proxy(target, handler);

proxy.getDate();
// TypeError: this is not a Date object.

// The getDate method is only available on the Date instance,
// An error is reported if this is not a Date object instance.
// Bind this to the original object to solve the problem

const target = new Date('2015-01-01');
const handler = {
  get(target, prop) {
    if (prop === 'getDate') {
      return target.getDate.bind(target);
    }
    return Reflect.get(target, prop); }};const proxy = new Proxy(target, handler);

proxy.getDate() / / 1
Copy the code