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.
defineProperty
与Object.definePropertySimilar, but when the object cannot be definedObject.defineProperty
Complains andReflect.defineProperty
No, it will returnfalse
Returns on successtrue
If it is not an object, an error will be reported.getPrototypeOf(target)
与Object.getPrototypeOf
Returns the prototype of the specified object.setPrototypeOf(target, prototype)
与Object.setPrototypeOf
Again, it sets the stereotype of the specified object to another object.getOwnPropertyDescriptor()
与Object.getOwnPropertyDescriptor
As such, returns the value of the given property if it exists in the objectAttribute descriptor.isExtensible(target)
与Object.isExtensible
Similarly, 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),Object
To force it into an object,Reflect
Error is reported directly.preventExtensions(target)
与Object.preventExtensions
Similarly, prevent new attributes from being added to the object, the difference being the same as before.apply(func, thisArg, args)
与Function.prototype.apply.call(fn, obj, args)
The same.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.
has(target, key)
与in
Operator, which makes judgment operations function behavior.deleteProperty(target, key)
与delete
Makes the delete operation function behavior, returning a Boolean value representing success or failure.construct(target, argumentsList[, newTarget])
与new
Same as the operator,target
Constructor. The second argument is the constructor argument class array. The third argument isnew.targetThe value of the.get(target, key[, receiver])
与obj[key]
Again, the third argument is what to valuekey
deployedgetter
To access its functionthis
The binding ofreceiver
Object.set(target, key, value[, receiver])
Set up thetarget
The object’skey
Attribute is equal to thevalue
, and the third argumentset
The 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:
Object.prototype.__proto__
Object.prototype.isPrototypeOf()
Object.getPrototypeOf()
Reflect.getPrototypeOf()
instanceof
The ownKeys method, which intercepts the read of an object’s own properties, intercepts the following operations:
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
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