javascript proxy : clear explanation and pratical examples

What is proxy

Proxy enalbes us to intercept and customize operations performed on objects (such as getting ,setting properties). They are metaprogramming feature.

metaProgramming:

Metaprogramming is writing a program which outputs another program , which enables one to intercept and define custome behavior for fundamental language operations(e.g. property lookup, assignment, enumeration, function invocation, etc).

The basic syntax

let proxy = new Proxy(target,handler)

  • target: is an object to wrap , can be anything ,including functions
  • handler: proxy configuration: an object with "traps", method that intercept operations. -e.g. get trap for reading property of target,set trap for writing a property into target,and so on .

for operations on proxy, if there's a corresponding trap in handler , then it runs ,and the proxy has the chance to handle it , otherwise the operation is performed on target.

At first , let's create a proxy without any traps:

let target = {};

let proxy = new Proxy(target,{}); // empty handler

proxy.test = 5;

console.log(target.test) // 5
console.log(proxy.test)  //5

As there are no traps , all operations on proxy are forwarded to target.

1.A writing operation proxy.test = sets the value on target.

2.A reading operation proxy.test returns the value from target .

Proxy is a special “exotic object”. It doesn’t have own properties. With an empty handler it transparently forwards operations to target.

To activate more capabilities , let's add traps. For most operations on object , there's a so-called 'internal method' in the javascript specification that describes how it works at the lowest level . For instance [[GET]], the internal method to read propery , [[SET]] , the internal method to write a property, and so on .

Proxy traps intercept invocations of these methods. They are listed in the below picture .

For every internal method, there's a trap in this table : the name of the method that we can add to the handler parameter of new Proxy to intercept the operation :

在这里插入图片描述

GET

The most common trap for reading the propery . The handler should have a method get(taregt,property,receiver)

  • target: the target object , the one passed as the first argument to new Proxy.
  • property : property name
  • receiver : optional , the proxy object itslef .

below , is a demo example . Usually if we try to get the non-existing array item , it returns undefined , but we will wrap a regular array into the proxy that traps reading and returns 0 if there's no such property .

let arr =[1,2,3,4];

let arr = new Proxy(arr,{
    get(target,prop){
       if(prop in target){
           return target[prop]
       }else{
           return 0;
       }
    }
})

let res1 = arr[0];
let res100 = arr[100];

console.log(res1);  //1

console.log(res100);  //0

SET

The most common trap for writing the property . THe handler should have a method set(target,property,value,receiver)

  • target: the target object , the one passed as the first argument to new Proxy.
  • property: property name.
  • value: the value that we want to assign to the property.
  • receiver: optional,the proxy object itslef .
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');
      }
    }

    // if valid,assign the vlaue to the property
    obj[prop] = value;
    return true;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

person.age // 100
person.age = 'young' // error
person.age = 300 // error

Those aboe are the most comomen ones and for more you can visit MDN DOCS

Reference

MDN

Javascript INFO

Proxy

js代理是一种元编程的能力,不少人知道但不知道怎么用,犀牛书也只是放了几个无卵用的demo,其实在做前端基础架构的时候会经常用到。下面讲几个我遇到的使用场景:

微前端沙箱机制

微前端是把一个大应用分成几个小应用进行开发的一套技术,他要做到在一个web基座上,运行几个相对独立子应用,每个子应用都是相对独立的工程,基座负责管理每个子应用的生命周期,以及环境和子应用之间的通信。把子应用接入基座常见的有html entry和jsentry两种方法,这里不展开说有兴趣可以自己去查。子应用接入到基座后相当于几个应用在共享一个全局环境,最直接的就是window(global的代理),为了给每个子应用分配独立的window,可以用到代理,劫持window,在set window的时候把修改的部分保存到另一个变量,这样就不会污染全局环境。

vue里的双向数据绑定

vue的state变化,要那些绑定了他的节点跟着重新渲染,这个时候用到观察者模式。代理(vue2用的defineproperty)劫持state,每个访问到state的节点保存到一个数组中,劫持set,改变state的时候就通知这个数组的节点,开始重新渲染。
其他应用还有很多,主要是用在劫持对象或某些操作(如网络层或通信)的时候,欢迎补充。

    clean
    其实,就是在set和get的时候,Vue不仅仅读和写其值,而是做更多的事情,比如你提到的数据渲染等

    7 天 后

    © 2018-2025 0xFFFF