es6 proxy小注及應用

js代理(Proxy)的做用是對基礎操做(取值,賦值,調用函數等)進行自定義。e.g. 你有一個對象obj = {},當對其屬性賦值時obj.age = 5,你但願作一些驗證好比age不能賦值爲string。這時代理就能夠幫上忙。javascript

用法

const p = new Proxy(target, handler);複製代碼

target:能夠是任意對象,包括數組,函數,或者另外一個代理html

handler:屬性是預約義函數的對象,它定義了這個代理的行爲。這個對象內的函數叫作陷阱(traps),由於你一旦對代理進行操做,相關的陷阱就會被觸發。java

來看一個最基本的例子,如上賦值obj.age = 5數組

const obj = {};
const proxy = new Proxy(obj, {
    set(target, key, value, receiver) {
        if (key === 'age') {
            if (!Number.isInteger(value)) {
                return false;
                // 或者 throw new TypeError('only allow int');
            }
            target[key] = value;
            return true;
        }
    }
});

proxy.age = 5; // OK
proxy.age = 'lol'; // 隱式賦值失敗,或拋錯複製代碼

set方法必須返回布爾值,表示賦值成功與否。返回false在嚴格模式下會拋錯TypeErrorbash

set函數的四個參數:app

target:你代理的真正對象,上面就是obj函數

key: 你訪問的代理屬性,如上ageui

value:給上面屬性賦的值,如上5this

receiver:被調用的對象,要麼是代理,要麼是繼承代理的對象。通常狀況下,如上,顯而易見就是proxy,可是某些狀況下代理並非最開始被調用的對象。e.g. 假設你賦值p.age = 5,p不是代理,p本身也沒有age屬性,可是p的原型鏈上有個代理,因此當那個代理的set被調用時,receiver實際上是p。spa


ps:賦值和返回true的的那句有些人喜歡寫成

return Reflect.set(target, key, value, receiver);複製代碼

上面這個基本等價於target[key] = value; 可是它返回設置成功與否,因此省了一步哈。

主要的陷阱函數

上面說了set,基本上全部對對象進行基本操做的方法都有相應的trap。這裏只談一下has(), get(), apply(), construct()

has

const obj = {_secret: 'hidden property', show: 'show'};
const proxy = new Proxy(obj, {
    has(target, key) {
        if (key[0] === '_') {
            return false;
        }
        return key in target;
    }
});

'_secret' in obj // false
'show' in obj // true複製代碼

這個trap是給in用的(不是for in),Reflect.has()也會觸發,上面例子基本上自我解釋了,很容易懂。必須返回boolean。

get

var p = new Proxy(target, {
  get: function(target, property, receiver) {
  }
});複製代碼

p.foo或p[bar]都會觸發。能夠返回任意值。

apply

var p = new Proxy(target, {
  apply: function(target, thisArg, argumentsList) {
  }
});複製代碼

p(),p.call(this), p.apply(this)均可觸發,能夠返回任意值。

construct

var p = new Proxy(target, {
  construct: function(target, argumentsList, newTarget) {
  }
});複製代碼

new一個實例的時候觸發,必須返回一個對象。

newTarget:被調用的構造器,如上p

應用

實現一個簡單的雙向綁定

<body> <input type="text" id="model"> <p id="word"></p> </body> <script> const model = document.getElementById("model") const word = document.getElementById("word") var obj= {}; const newObj = new Proxy(obj, { set: function(target, key, value, receiver) { if (key === "text") { model.value = value; word.innerHTML = value; } return Reflect.set(target, key, value, receiver); } }); // change ui will change local object model.addEventListener("keyup",function(e){ newObj.text = e.target.value }) // later on, if you want to programmaticly change local object, it will also reflect on UI newObj.text = 'something i like'; </script>複製代碼

取得輸入框和顯示框元素,給輸入框加監聽,若是用戶輸入了,那麼對代理的text屬性賦值, 這是ui改js,若是後面用戶想直接修改newObject,其改動也會反映在UI上,由於代理內部有給元素賦值。

相關文章
相關標籤/搜索