Overview: Find the default behavior

Reflect objects, like Proxy objects, are a new API provided by ES6 for manipulating objects.

Reflect finds the default behavior

The characteristics of

(1)ObjectSome methods of the object that are clearly internal to the language (e.gObject.defineProperty), inReflectOn the object

(2)Modify theSome of theObjectmethodsReturns the result“To make it more reasonable.

Object.defineProperty(obj, name, desc)An error is thrown if the attribute cannot be defined, andReflect.defineProperty(obj, name, desc)Will returnfalse

/ / the old way
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // failure
}

/ / a new way
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // failure
}
Copy the code

(3)Make all operations of Object function behavior

Some Object operations are imperative, such as

1.name in objbeReflect.has(obj, name)Student: Substitution becomesFunction behavior

2,delete obj[name]beReflect.deleteProperty(obj, name)Student: Substitution becomesFunction behavior

/ / the old way
'assign' in Object // true

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

(4)The methods of the Reflect object correspond to those of the Proxy object

Reflect exists as a static method, which can be found on a Proxy object as long as it is a Proxy object.

This allows the Proxy object to easily call the corresponding Reflect method to perform the default behavior. No matter how the Proxy modifies the default behavior, you can always get the default behavior at Reflect.

The default method that Reflects calls the object skips Proxy interception

Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target,name, value, receiver);
    if (success) {
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    returnsuccess; }});Copy the code

In the code above, the Proxy method intercepts the attribute assignment behavior of the target object. It uses the reflect.set method to assign values to the properties of the object, ensuring that the original behavior is complete, and then deploys additional functionality.

Feature 4 Example

Output one line of log for each operation without making any changes.

Each intercept operation (GET, DELETE, has) on a Proxy object internally invokes the corresponding Reflect method to ensure the normal execution of the native behavior.

var loggedObj = new Proxy(obj, {
  get(target, name) {
    console.log('get', target, name);
    return Reflect.get(target, name);
  },
  deleteProperty(target, name) {
    console.log('delete' + name);
    return Reflect.deleteProperty(target, name);
  },
  has(target, name) {
    console.log('has' + name);
    return Reflect.has(target, name); }});Copy the code

A static method

Most methods with the same name as Object objects have the same function, and it corresponds to Proxy objects in a one-to-one way. Find the corresponding default method and execute it.

  • Reflect.apply(target, thisArg, args)
  • Reflect.construct(target, args)
  • Reflect.get(target, name, receiver)
  • Reflect.set(target, name, value, receiver)
  • Reflect.defineProperty(target, name, desc)
  • Reflect.deleteProperty(target, name)
  • Reflect.has(target, name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)

Reflect.get(target, name, receiver)

The reflect. get method looks for and returns the name property of the target object, or undefined if it doesn’t exist.

Target must be an object

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

Reflect.set(target, name, value, receiver)

Set the name attribute of the target object to value.

The first argument target is not an object. Reflect.set will report an error.

// The fourth parameter 'receiver' is not specified
var myObject = {
  foo: 1.set bar(value) {
    return this.foo = value;
  },
}

myObject.foo / / 1

Reflect.set(myObject, 'foo'.2);
myObject.foo / / 2

Reflect.set(myObject, 'bar'.3)
myObject.foo / / 3
Copy the code

ifnameProperty sets the assignment function, thenAssign this to the functionPoint to the fourth parameterreceiver

// A fourth parameter, 'receiver', is specified
var myObject = {
  foo: 4.set bar(value) {
    return this.foo = value; }};var myReceiverObject = {
  foo: 0};Reflect.set(myObject, 'bar'.1, myReceiverObject);
myObject.foo / / 4
myReceiverObject.foo / / 1
Copy the code

ProxyThe objects andReflectObject association

The former intercepts assignment, the latter completes the default behavior of assignment,

Reflect.setIntroduced to thereceiverArgument, then will fireProxy.definePropertyInterception,

No receiver is passed in, then a defineProperty interception is not triggered.

let p = {
    a:'a'
}

let handler ={
    set(target,key,value,receuver){
        console.log('set')
        Reflect.set(target,key,value,recever)  // Pass receuveri: print set -> assign -> defineProperty
        Reflect.set(target,key,value)// Do not pass receuveri: print set -> assignment
    },
    defineProperty(target,key,attribute){
        console.log('defineProperty');
        Reflect.defineProperty(target, key, attribute); }}let obj =new Proxy(p,handler);
obj.a='A';

Copy the code

Reflect.has(obj, name)

Corresponds to the in operator in name in obj.

The reflect. has and in operators will both report an error if the first argument is not an object.

var myObject = {
  foo: 1};/ / the old way
'foo' in myObject // true

/ / a new way
Reflect.has(myObject, 'foo') // true

Copy the code

Reflect.apply(func, thisArg, args)

Three arguments: the object function, the context object (to which this points), and the argument array

Reflect.applyMethod equivalent toFunction.prototype.apply.call(func, thisArg, args), for bindingthisObject to execute the given function

In general, if you want to bind a Function of this object, you can write fn. Apply (obj, args), but if a Function defined my own way to apply, you can only write the Function. The prototype. Apply. Call (fn, obj, args), Using the Reflect object simplifies this operation.

const ages = [11.33.12.54.18.96];

/ / the old way
const youngest = Math.min.apply(Math, ages);
const oldest = Math.max.apply(Math, ages);
const type = Object.prototype.toString.call(youngest);

/ / a new way
const youngest = Reflect.apply(Math.min, Math, ages);
const oldest = Reflect.apply(Math.max, Math, ages);
const type = Reflect.apply(Object.prototype.toString, youngest, []);
Copy the code

Reflect.construct(target, args)

The reflect. construct method is equivalent to new target(… Args), which provides a way to call the constructor without using new.

function Greeting(name) {
  this.name = name;
}

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

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

Reflect.deleteproperty (obj, name), equivalent to delete obj[name]

The reflect. deleteProperty method is equivalent to delete obj[name], used to delete an object’s property. This method returns a Boolean value. Returns true if the deletion succeeded or if the deleted attribute does not exist; Failed to delete, the deleted property still exists, return false.

const myObj = { foo: 'bar' };

/ / the old way
delete myObj.foo;

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

Reflect.getprototypeof (obj), which reads the object__proto__attribute

Used to read the __proto__ property of an Object, corresponding to Object.getProtoTypeof (obj).

const myObj = new FancyThing();

/ / the old way
Object.getPrototypeOf(myObj) === FancyThing.prototype;

/ / a new way
Reflect.getPrototypeOf(myObj) === FancyThing.prototype;
Copy the code

Reflect.getprototypeof differs from Object.getPrototypeof:

If the parameter is not an Object, Object.getProtoTypeof will turn the parameter into an Object and run again, and reflect.getPrototypeof will report an error.

Object.getPrototypeOf(1) // Number {[[PrimitiveValue]]: 0}
Reflect.getPrototypeOf(1) / / an error
Copy the code

Reflect.setprototypeof (obj, newProto), sets the target object’s prototype (prototype)

SetPrototypeOf (obj, newProto) method used to set the Object’s prototype.

Returns a Boolean value indicating whether the setting was successful.

const myObj = {};

/ / the old way
Object.setPrototypeOf(myObj, Array.prototype);

/ / a new way
Reflect.setPrototypeOf(myObj, Array.prototype);

myObj.length / / 0
Copy the code

If the first argument is not an Object, Object.setPrototypeof returns the first argument itself, and reflect.setPrototypeof returns an error.

Object.setPrototypeOf(1, {})
/ / 1

Reflect.setPrototypeOf(1, {})
// TypeError: Reflect.setPrototypeOf called on non-object
Copy the code

Object.setPrototypeOf and reflect. setPrototypeOf will both fail if the first argument is undefined or null.

Reflect.defineProperty(target, propertyKey, attributes)

Reflect.defineproperty is basically equivalent to Object.defineProperty and is used to define attributes for an Object. Object.defineproperty will be phased out in the future, so use Reflect.defineProperty instead from now on.

If the first argument is not an object, an error is thrown

function MyDate() {
  / *... * /
}

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

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

Proxy.defineproperty sets the interception for attribute assignment and then completes the assignment using reflect.defineProperty

const p = new Proxy({}, {
  defineProperty(target, prop, descriptor) {
    console.log(descriptor);
    return Reflect.defineProperty(target, prop, descriptor); }}); p.foo ='bar';
// {value: "bar", writable: true, enumerable: true, configurable: true}

p.foo // "bar"
Copy the code

Reflect. GetOwnPropertyDescriptor (target, propertyKey), get the specified attributes describe objects

Reflect. GetOwnPropertyDescriptor basic equivalent to the Object. GetOwnPropertyDescriptor, used to get the specified attributes describe objects, will replace the latter in the future.

The first parameter is not Object, the Object. GetOwnPropertyDescriptor (1, ‘foo’) is not an error, return to undefined, and Reflect. GetOwnPropertyDescriptor (1, ‘foo’) will throw an error, The parameter is invalid.

var myObject = {};
Object.defineProperty(myObject, 'hidden', {
  value: true.enumerable: false});/ / the old way
var theDescriptor = Object.getOwnPropertyDescriptor(myObject, 'hidden');

/ / a new way
var theDescriptor = Reflect.getOwnPropertyDescriptor(myObject, 'hidden');
Copy the code

Reflect.isextensible (target) : indicates whether the current object isExtensible

The reflect. isExtensible method corresponds to object. isExtensible, which returns a Boolean value indicating whether the current Object isExtensible.

Object. IsExtensible returns false if the argument is not an Object, since non-objects are inherently unextensible, and Reflects. isExtensible returns an error.

const myObject = {};

/ / the old way
Object.isExtensible(myObject) // true

/ / a new way
Reflect.isExtensible(myObject) // true
Copy the code

Reflect. PreventExtensions (target), make an object into an extension

Reflect. The corresponding Object preventExtensions. PreventExtensions method, used to make an Object into an extension. It returns a Boolean value indicating whether the operation succeeded.

var myObject = {};

/ / the old way
Object.preventExtensions(myObject) // Object {}

/ / a new way
Reflect.preventExtensions(myObject) // true
Copy the code

If the parameter is not Object, the Object preventExtensions error in ES5 environment, return to the incoming parameters on ES6 environment, and Reflect. PreventExtensions complains.

Reflect.ownkeys (target), which returns the names of all the properties of the object

Reflect the ownKeys method to return all attributes of the Object, basic is equal to the Object. The getOwnPropertyNames with Object. GetOwnPropertySymbols combined.

var myObject = {
  foo: 1.bar: 2[Symbol.for('baz')]: 3[Symbol.for('bing')]: 4};/ / the old way
Object.getOwnPropertyNames(myObject)
// ['foo', 'bar']

Object.getOwnPropertySymbols(myObject)
//[Symbol(baz), Symbol(bing)]

/ / a new way
Reflect.ownKeys(myObject)
// ['foo', 'bar', Symbol(baz), Symbol(bing)]
Copy the code

Use Proxy to implement the observer pattern

Observer Mode:

A function that automatically observes a data object and executes it whenever the object changes.

The data object person is the observation target, and the function print is the observer. Print is automatically executed as soon as the data object changes. The simplest implementation of the observer pattern is to write a Proxy that implements the observable and observe functions. The idea is that the Observable function returns a Proxy of the original object, intercepts assignment, and triggers functions that act as observers.

// Define a Set for all observer functions
const queuedObservers = new Set(a);const observe = fn= > queuedObservers.add(fn);

function set(target, key, value, receiver){
    const result = Reflect.set(target, key, value, receiver);
    queuedObservers.forEach(observer= > observer());
    return result;
}
const observable = obj= > new Proxy(obj,{set});

const person = observable({
  name: 'Joe'.age: 20
});

function print() {
  console.log(`${person.name}.${person.age}`)
}

observe(print);
person.name = 'bill';
/ / output
// Li Si, 20
Copy the code