[重学前端基础] Javascript之Proxy

认识Proxy

能够把Proxy看做是一个拦截器,能够对目标对象的访问进行过滤和改写。proxy实例能够拦截对象的属性读取、赋值、删除、经过definedProperty定义等操做外,还能够拦截到对象被看成方法调用仍是构造函数使用等操做。那Proxy具体怎么用的呢?javascript

Proxy的用法

经过Proxy来监测对象的赋值和读取

入门例子:给目标对象添加属性并赋值vue

var obj = new Proxy({}, {
    get: function (target, propKey, receiver) {
        console.log(`getting ${propKey} value: ${target[propKey]}!`);
        return Reflect.get(target, propKey, receiver);
    },
    set: function (target, propKey, value, receiver) {
        console.log(`setting ${propKey} value: ${value}!`);
        return Reflect.set(target, propKey, value, receiver);
    }
});
obj.count = 1
++obj.count

//setting count value: 1!
//getting count value: 1!
//setting count value: 2!

Proxy的特色

new Proxy(第一个参数, 第二个参数),第一个参数为目标对象,第二个参数为操做对象的行为的对象。java

Proxy构造函数的第一个参数为目标对象,和new出来的Proxy实例是同一个对象,但要注意只有修改Proxy实例值才会触发对应的拦截的方法:es6

var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';
target.a // "b"

Proxy实例也能够作为其余对象的原型对象:web

var proxy = new Proxy({}, {
  get: function(target, propKey) {
    return 35;
  }
});

let obj = Object.create(proxy);
obj.time // 35

能够设置多个拦截操做,例如:拦截对象做为方法使用、做为构造函数使用、做为对象操做属性等操做,能够在函数中return指定值:json

var handler = {
  get: function(target, name) {
    if (name === 'prototype') {
      return Object.prototype;
    }
    return 'Hello, ' + name;
  },

  apply: function(target, thisBinding, args) {
    return args[0];
  },

  construct: function(target, args) {
    return {value: args[1]};
  }
};

var fproxy = new Proxy(function(x, y) {
  return x + y;
}, handler);

fproxy(1, 2) // 1
new fproxy(1, 2) // {value: 2}
fproxy.prototype === Object.prototype // true
fproxy.foo === "Hello, foo" // true

触发Proxy实例set的状况和触发Proxy实例get的状况:数组

  • 触发Proxy实例set的状况:给实例添加属性或对已存在属性进行从新赋值时,不管属性的值是什么类型都会触发set。
  • 触发Proxy实例get的状况:读取Proxy实例中的属性时(不管属性是否已经存在)、除了以上触发set的方法,其余赋值行为都会触发get(具体见下面例子各类赋值状况)。
var data = {
    odata: {
        name: 'odata',
        age: '21'
    },
    arr: [{
        name: 'youyi',
        age: '24'
    }],
    name: 'bb'
}

var obsever = new Proxy(data, {
    get: function (target, propKey, receiver) {
        console.log('get:', target[propKey])
        return Reflect.get(target, propKey, receiver);
    },
    set: function (target, propKey, value, receiver) {
        console.log('set:', value)
        return Reflect.set(target, propKey, value, receiver);
    }
})

以上的结果:app

赋值却触发proxy实例get方法的状况
一、对proxy实例中的数组进行操做:函数

image.png

image.png

image.png

二、对proxy实例中的对象的属性进行操做:
image.pngthis

赋值触发proxy实例set方法:修改proxy实例的属性的整个值或新增一个属性并赋值时

一、修改proxy实例的数组类型属性
image.png

二、修改proxy实例的对象类型属性
image.png

Proxy的应用场景

  • 实现相似Promise链式调用
var pipe = (function () {
  return function (value) {
    var funcStack = [];
    var oproxy = new Proxy({} , {
      get : function (pipeObject, fnName) {
        if (fnName === 'get') {
          return funcStack.reduce(function (val, fn) {
            return fn(val);
          },value);
        }
        funcStack.push(window[fnName]);
        return oproxy;
      }
    });

    return oproxy;
  }
}());

var double = n => n * 2;
var pow    = n => n * n;
var reverseInt = n => n.toString().split("").reverse().join("") | 0;

pipe(3).double.pow.reverseInt.get; // 63
  • 利用get拦截返回函数,实现web客户端
const service = createWebService('http://example.com/data');

service.employees().then(json => {
  const employees = JSON.parse(json);
  // ···
});


function createWebService(baseUrl) {
  return new Proxy({}, {
    get(target, propKey, receiver) {
      return () => httpGet(baseUrl + '/' + propKey);
    }
  });
}
  • 实现相似vue中的响应式

参考资料:

ES6之proxy

抱歉,学会 Proxy 真的能够随心所欲

相关文章
相关标签/搜索