This is the 14th day of my participation in Gwen Challenge

Relearn JavaScript in a series of articles…

DefineProperty: Proxy and Object. DefineProperty: Proxy and Object.

A Proxy is a wrapper that intercepts and changes the operations of the underlying JavaScript engine, exposing the inner workings of objects in a new language.

Proxy

Proxy is mainly used to change the default access behavior of objects. In fact, it adds a layer of interception before accessing objects. Any access behavior of objects will pass through this layer of interception. In this layer of interception, we can add custom behavior.

The basic syntax is as follows:

/* * proxy: instance of proxy constructor */ var proxy = new proxy (target,handler)Copy the code

Basic usage

Here’s a simple example:

Var target = {num:1} // Custom access interceptor var handler = {// receiver: The object on which the operation takes place, Get :function(target,prop,receiver){console.log(target,prop,receiver) return target[prop]*2}, set:function(trapTarget,key,value,receiver){ console.log(trapTarget.hasOwnProperty(key),isNaN(value)) if(! trapTarget.hasOwnProperty(key)){ if(typeof value ! = = 'number') {throw new Error (' into the parameter must be a number ')} return Reflect. Set (trapTarget, key and the value, the receiver)}}} / / DobuleTarget var dobuleTarget = new Proxy(target,handler) console.log(dobuletarget.num) // 2 Console. log(dobuleTarget) {num: 1, count: 2} console.log(target) // {num: 1, count: C = 2 console.log(dobuletarget.c) // 4 can listen to the new attribute of targetCopy the code

In this example, we use the Proxy constructor to create target’s Proxy dobuleTarget, that is, to Proxy the entire target object. In this case, access to the dobuleTarget property is forwarded to target, and a custom handler object is configured for the access behavior. So any access to a target object’s property via dobuleTarget will perform the handler object’s custom interception.

The technical description is:

Proxies can intercept low-level object operations on targets within the JavaScript engine, which, when intercepted, trigger trap functions in response to specific operations. The trap function in this example is the get function.

Trap function summary

To summarize the trap functions of Proxy:

Trap function The nature of overwriting
get Read a value
set Write a value
has The in operator
deleteProperty Object.getPrototypeOf()
getPrototypeOf Object.getPrototypeOf()
setPrototypeOf Object.setPrototypeOf()
isExtensible Object.isExtensible()
preventExtensions Object.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor()
defineProperty Object.defineProperty
ownKeys Object. The keys () Object. GetOwnPropertyNames () and Object. The getOwnPropertySymbols ()
apply Call a function
construct Call a function with new

Trap function application

Hide private attributes, and do not allow deletion

Var obj = {// Private attributes start with "_". _type:'obj', name:'hello world'} var handler = { Has :function(trapTarget,prop){if(prop[0]=== '_'){return false} return prop in trapTarget}, DeleteProperty :function(trapTarget,prop){if(prop[0]=== '_'){throw new Error(' private properties cannot be deleted ')} return true }} var proxy = new proxy (obj,handler) '_type' in proxy // false delete proxyCopy the code

Proxy Indicates a recursive Proxy

Proxy Proxies only the outer properties of the object. Examples are as follows:

var target = { a:1, b:{ c:2, D :{e:3}}} var handler = {get:function(trapTarget,prop,receiver){console.log(' get:',prop) return Reflect.get(trapTarget,prop) }, Set: function (trapTarget, key and the value, the receiver) {the console. The log (' trigger set: 'key, value) return Reflect. Set (trapTarget, key and the value, the receiver)}} var proxy = new proxy (target, handler) proxy. B.D.E = 4 / / output to trigger the get: b, This shows that the Proxy only represents the outer attributes of the object.Copy the code

How to solve it? Recursively set up the proxy

var target = { a:1, b:{ c:2, d:{e:3} } } var handler = { get:function(trapTarget,prop,receiver){ var val = Reflect.get(trapTarget,prop) console.log('get',prop) if(val ! == null && typeof Val ==='object'){return new Proxy(val,handler) // Proxy inner} return reflect. get(trapTarget,prop)}, Set: function (trapTarget, key and the value, the receiver) {the console. The log (' trigger set: 'key, value) return Reflect the set (trapTarget, key and the value, the receiver)}} var proxy = new proxy (target, handler) proxy. B.D.E / / output: All proxies // get b // get d // get eCopy the code

As you can see from the recursive Proxy, if you want all the recursive proxies inside an object, the Proxy can recursively set the Proxy only at call time.

Object.defineProperty

Object.defineproperty () directly defines new properties on the Object, or modifies existing properties on the Object, and then returns the Object.

The syntax is as follows:

/* * obj: the object on which properties are to be defined * prop: The name or Symbol * descriptor of the property to be defined or modified: Descriptor for defined or modified properties */ Object.defineProperty(obj, prop, Descriptor)Copy the code

The descriptor

There are two types of descriptors in an object: data descriptors and access descriptors. A descriptor can only be one of the two, not both, and both descriptors are objects.

Data descriptor: A property that has a value and whether the value is writable.

Access descriptors: Properties described by getter and setter functions.

Descriptors share the following attributes:

  1. Different (default false)

Is configurable? If it is true, the attribute descriptor can be changed and the attribute can be deleted from the corresponding object.

  1. Enumerable (default false)

Enumerable or not. If true, the property will appear in the enumerated properties of the object

Data descriptor

Data descriptor Optional key values:

  1. Value (default undefined)

Property, which can be any valid JavaScript value. 2. Value can only be changed by assignment operators if the writable key is true.

Access descriptor optional key values:

  1. Get (default undefined)

Property’s getter() function, which is called when the property is accessed. The return value returned is used as the value of the property.

  1. Set (default undefined)

Property, which is called when the property is modified.

Basic usage

Var obj = {} object.defineProperty (obj,'name',{value:' zhang SAN '}) obj.name // 'Zhang SAN' obj.name = 'Li Si' // assign a new value to obj.name Console. log(obj.name) // Output: DefineProperty (obj,'name',{value:' name', writable:false, 64x: 64x) {// defineProperty(obj,'name',{value:' name', writable:false, 64x: 64x) false, enumerable: false })Copy the code

Object.defineproperty can only be proxyed for a property on an Object, so if internal attributes are proxyed, all attributes can be proxyed recursively at once.

Custom setters and getters

function Archiver() { var log = null; var archive = []; Object.defineProperty(this, 'log', { get() { console.log('get log! '); return log; }, set(value) { log = value; archive.push({ val: log }); }}); this.getArchive = function() { return archive; }; } var arc = new Archiver(); arc.log; // 'get log! ' arc.log = 'log1'; arc.log = 'log2'; arc.getArchive(); // [{ val: 'log1' }, { val: 'log2'}]Copy the code

conclusion

  1. A Proxy is a Proxy for an entire Object, while Object.defineProperty can only be a Proxy for a property.
  2. Object defineProperty adds attributes that Proxy can listen for but object.defineProperty cannot.
  3. Object. DefineProperty does not.
  4. If the internal properties of an Object need to be recursively Proxy, the Proxy can recurse only when called, whereas Object.definePropery needs to do all recursion at once, which is worse than Proxy performance.
  5. Proxy is not compatible with IE, Object. DefineProperty is not compatible with IE8 and below
  6. Proxy is much more convenient to use than Object.defineProperty.