[重學前端基礎] 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 真的能夠隨心所欲

相關文章
相關標籤/搜索