Concept of agency

Macro: Design patterns

Proxy mode: a proxy object is provided to control access to an object when it is inconvenient for users to directly access the object or when the need is not met. The user actually accesses the proxy object

Key: Both the proxy object and the ontology provide a behavior [method] externally, and separate different behaviors from the idea of the subject through the proxy layering

Simple implementation of a native proxy:

const mult = function () {
  console.log("Let's compute the product.");
  let a = 1;
  for (let i = 0, l = arguments.length; i < l; i++) {
    a = a * arguments[i];
  }
  return a;
};

const  proxyMult = (function () {
   console.log(Create proxy space and assign it to proxyMult);
  const cache = {};
  return function () {
   console.log("Access proxy");
   const args = Array.prototype.join.call(arguments.",");
    if (args in cache) {
      return cache[args];
    }
    return (cache[args] = mult.apply(this.arguments)); }; }) (); proxyMult(11); 
proxyMult(1.1); 
Copy the code

Micro: ES6 new syntax – Proxy

To create the agent

Creating an empty proxy allows all operations to reach the target object

const target={ // Represents the object to which the proxy is to be added
    id:'target'.o: {}};const handler={};/ / capture device
Const proxy=new proxy (target,Reflect);
const proxy=new Proxy(target,handler); // The Proxy constructor creates the Proxy (target object and handler object)
console.log(target.o === proxy.o);//true proxy can get target object notice {}! = = {}
console.log(target === proxy);// Strict mode can distinguish between agents and targets
Copy the code

Define trap

One basic operation corresponds to one interceptor, and each handler object can contain one or more interceptors. e.g: get

const target={
    foo:'bar'
};

const handler={
    // The get trap is triggered by the basic operation GET with the method name key
    get(){// Get for all properties of the agent
        return 'handle override'; }};const proxy=new Proxy(target,handler);// The Proxy constructor creates the Proxy (target object and handler object)
console.log(target.foo);//bar
console.log(proxy.foo);//handle override
console.log(proxy.f);//handle override
Copy the code

The reflection API

Instead of manually recreating the original behavior, developers can do so by calling a method of the same name on the global Reflect object. The reflection API has boilerplate code ready for developers to modify the capture method with minimal code.

// Object
var obj = { x: 1.y: 2 };
Reflect.get(obj, "x"); / / 1

// Array
Reflect.get(["zero"."one"].1); // "one"

// Proxy with a get handler
var x = {p: 1};
var obj = new Proxy(x, {
// get: Reflect.get
  get(t, k, r) { 
      return t[k] + "bar";
      // return Reflect.get(... arguments);}});Reflect.get(obj, "foo"); // "foobar"
Copy the code

Prototype. Most of the reflection API methods have corresponding methods on type Object. Methods on Object are suitable for general-purpose programs, while reflection methods are suitable for fine-grained object control and manipulation.

Status flags: Returns a Boolean value – whether the operation was successful partial reflection methods provide status flags:

Reflect.defineProperty();
Reflect.deleteProperty();/ / delete operator
Reflect.preventExtensions();
Reflect.setPrototypeOf();
Reflect.set();
Copy the code
Reflect.getPrototypeOf();
Reflect.get();// Instead of object attribute access // more direct, without going through the GET trap
Reflect.has();/ / with, in
Reflect.construct(); //new
Reflect.getOwnPropertyDescriptor();
Reflect.ownKeys();
Reflect.isExtensible();
Reflect.apply();
Copy the code

Revoke proxy.revocable

A normal Proxy created by new Proxy(), where the connection between the Proxy object and the target object persists for the lifetime of the Proxy object.

The proxy.revocable () method can be used to create a revocable Proxy object.

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

revocable.revoke();

console.log(proxy.foo); / / throw TypeError
proxy.foo = 1           / / or TypeError
delete proxy.foo;       / / and a TypeError
typeof proxy            // "object", because typeof is not a proxy operation
Copy the code

The REVOKE method causes the proxy to be automatically reclaimed, and any subsequent calls end with TypeError.

Nested agent

Proxy Another proxy: Creates multiple layers of interceptor nets over a target object

const target={
    foo:'bar'
};

const proxy1=new Proxy(target,{
    get(){
        console.log("first proxy");
        return Reflect.get(... arguments);/ / access to the target}});// The Proxy constructor creates the Proxy (target object and handler object)

const proxy2=new Proxy(proxy1,{
    get(){
        console.log("second proxy");
        return Reflect.get(... arguments);/ / access proxy1}});// The Proxy constructor creates the Proxy (target object and handler object)

console.log(proxy2.foo);
//second proxy
//first proxy
//bar
Copy the code

This problem in the proxy

Method this refers to the object calling the method, so this refers to the proxy when the proxy executes target’s code

Associate a proxy instance that weakly references a proxy instance and a proxy class that simultaneously differentiates between a proxy instance and a proxy class

const wm = new WeakMap(a);class User {
  constructor(userId) {
    wm.set(this, userId);
  }

  set id(userId) {
    wm.set(this, userId);
  }

  get id() {
    return wm.get(this); }}const myuser = new User(123);
console.log(myuser.id);  / / 123
const userInstanceProxy = new Proxy(myuser, {});// Proxy an instance
console.log(userInstanceProxy.id);  // undefined
const UserProxy = new Proxy(User, {});/ / the proxy class
console.log(UserProxy.id);  // undefined
const xx=new UserProxy(456);// Instantiate the proxy class
console.log(xx.id);  / / 456
Copy the code

Proxy and internal slot Proxy and partial built-in types may rely on mechanisms beyond the control of the proxy. LLDB :Date Class method execution depends on the internal slot [NumberDate], which does not exist on the proxy object.

const target = new Date(a);const proxy = new Proxy( target, {});
console.log(proxy instanceof Date);
proxy.getDate(); // Uncaught TypeError: this is not a Date object
Copy the code

application

Trace property access

Capture operations such as GET, set, and HAS

const user={
    name:'jake'
};

const proxy=new Proxy(user,{
    get(target,property,receiver){
        console.log('getting ${property}');
        return Reflect.get(... arguments); },set(target,property,value,receiver){
        console.log('setting ${property}=${value}');
        return Reflect.set(... arguments); }//has
});


proxy.name;//getting name
Copy the code

Hidden attribute

The internal implementation of the proxy is invisible to external code, so it is easy to hide properties on the target object. Involves has and GET functions

const hidden=['foo'.'bar'];// Hide the property list
const target={
    foo:1.bar:2.baz:3
};
const proxy=new proxy(target,{
    get(target,property){
        if(hidden.includes(property)){
            return undefined;
        }else{
            return Reflect.get(...arguments);
        }
    },
    has(target,property){
        if(hidden.includes(property)){
            return false;
        }else{
            return Reflect.has(... arguments); }}});Copy the code

Property verification

All assignment operations trigger the set catcher, which can decide whether to deny or allow based on the assigned value

Constructor parameter validation

Arguments to functions and constructors are also examined.

Data binding, observable.

Agents link otherwise unrelated parts of a run together, enabling patterns to be implemented and code to interoperate.

Bind the proxied class to a global instance collection to which all created instances are added

const userList=[];
class User{
    constructor(name){
        this.name_=name; }}// Create a proxy for the class
const proxy=new Proxy(User,{
    constructor(){
        const newUser=Reflect.construct(... arguments); userList.push(newUser);returnnewUser; }});Copy the code

Image preloading

The virtual proxy considers that the network is not good or the image is too large, so the image cannot be loaded at the moment. It uses a loading image to occupy the space, and then loads the image asynchronously. After the image is loaded, it is filled into the IMG node

        const myImage = (function(){
    		const imgNode = document.createElement( 'img' );
    		document.body.appendChild( imgNode );
 
    		return {
    			setSrc: function( src ){
    				imgNode.src = src;
    			}
    		};
    	})();
 
    	const proxyImage = (function(){
    		const img = new Image;
    		img.onload = function(){ // triggered immediately after loading http://finlly.jpg
    			myImage.setSrc( this.src );
    		};
    		return {
    			setSrc: function( src ){
    				myImage.setSrc( 'Placeholder for proxy object Settings. JPG' );   
    				img.src = src;
    			}
    		};
    	})();
    	proxyImage.setSrc( 'http://finlly.jpg' );            
Copy the code

Control the right to call a function

Proxy targets are functions, and functions are objects in nature

When using a trusted third party library, we need to pass a function to the library that is not under our control. We can pass a revocation proxy function to him. After using the library, we can revoke the proxy, preventing the third party library from holding a reference to our function and calling it when we do not know.

function accessTheDatabase(){
    // Our important function
}

const {proxy, revoke} = Proxy.revocable(accessTheDatabase, {}); // proxy important functions

Copy the code

Proxy capture and reflection methods

get()

Trap infinitive: If target.property is unwritable and unconfigurable, the value returned by the handler must match target.property

Property proxy[property] Object. Create (proxy)[property] reflect. get(proxy,property,receiver)Copy the code

The catcher handler parameter

  • The target object
  • String key properties
  • Proxy object Receiver

set()

Trap infinitives cannot be modified if target.property is not writable and configurable

Returns a Boolean value, whether the operation succeeded or not

Intercepting operations: proxy.property=value proxy[property]=value Object.create(proxy)[property]=value Reflect.set(proxy,property,value,receiver)Copy the code
const target = {};
Object.defineProperty(target,"foo",{
	writable:true,
	value:"bar"
	});
const handler = {
  get(trapTarget, property, receiver) {
    return trapTarget[property];
  },
  set(trapTarget,property,value,receiver) {
    console.log("set");
    return Reflect.set(...arguments);
  }
};

const proxy = new Proxy(target, handler);
console.log(proxy.foo);   // bar
console.log(target.foo);  // bar 
proxy.foo="ywy";
console.log(proxy.foo);   // ywy
console.log(target.foo);  // ywy 

Copy the code

has()

Returns a Boolean value indicating whether the attribute exists

Property in proxy property in object. create(proxy) with(proxy){(property); } Reflect.has(proxy,property)Copy the code

defineProperty()

Trap infinitives cannot define properties if the target object is not extensible

Returns a Boolean value, whether the operation succeeded or not

Intercepting operations: DefineProperty (proxy,property, descriptor) reflect.defineProperty (proxy,property, descriptor) Descriptor)// Descriptor contains optional enumerable, 64x, writable, value, get, and set definitionsCopy the code

getOwnPropertyDescriptor()

Return object, or undefined

Interception of operation: Object. GetOwnPropertyDescriptor (proxy, property) Reflect. GetOwnPropertyDescriptor (proxy, the property)Copy the code

deleteProperty()

Returns a Boolean value, whether to delete

Delete proxy[property] reflect.deleteProperty (proxy,property)Copy the code

ownKeys()

Capture infinitives: The returned enumerable object must contain exactly all of Target’s own non-configurable properties. If Target is not extensible, the returned enumerable object must contain exactly free property keys

Returns an enumerable object containing a string or symbol

Interception of operation: Object. GetOwnPropertyNames (proxy) Object. GetOwnPropertySymbols (proxy) Object. Keys (proxy) Reflect. OwnKeys (proxy)Copy the code

getPrototypeOf()

Return object or NULL

Intercepted operation: proxy.__ proto __Copy the code

setPrototypeOf()

Returns a Boolean to see if the prototype assignment was successful

isExtensions()

Returns Boolean, whether it can be expanded

preventExtensions()

Return to Boolean to see if it has not been able to expand

apply()

The catch infinitive target must be a function object

Caught while calling the proxy

function median(... nums) { return nums.sort()[Math.floor(nums.length / 2)]; } console.log("proxy pre-median: "+median(4, 7, 1)); // 4 let count=0; const proxy = new Proxy(median, { apply(target, thisArg, ... argumentsList) { console.log("this proxy apply"); return Reflect.apply(... arguments); }}); Console. log(" post-proxy median: "+median(4, 7, 1)); // 4 console.log(proxy(4, 7, 1)); //this proxy apply 4Copy the code

construct()

Return an object

Intercepting operations:newproxy(... argumentsList) Reflec.construct(target,argumentsList,newTarget)Copy the code