https://segmentfault.com/a/11...
Vue3.0應該立刻就要發佈正式版了。據說在新版本中,Proxy取代了Object.defineProperty
進行雙向綁定。主要緣由應該是Object.defineProperty
在處理數組響應是會存在缺陷。javascript
let demo = {}; let arr = []; Object.defineProperty(demo, "arr", { get: function() { return arr; }, set: a => { console.log("hear set"); arr = a; }, configurable: true, enumerable: true }); demo.arr = [1, 2, 3, 4]; // => 'hear set'; console.log(arr === demo.arr); // => true /* 經過索引修改數組,沒法觸發set */ demo.arr[2] = null; // => 沒有輸出hear set。 console.log(arr === demo.arr); // => true /* 經過push,pop,sort等方法一樣沒法觸發set */ demo.arr.push("13"); // => 沒有輸出hear set。
http://es6.ruanyifeng.com/#do...
Proxy
原意爲代理,在實際操做中,能夠理解爲,在目標數據前增長一個攔截器。經過攔截器,能夠實現監聽、修改目標數據。java
let obj = new Proxy( {}, { set: function(target, key, receiver) { console.log(`set key ${key}`); return Reflect.set(target, key, receiver); }, get: function(target, key, receiver) { console.log(`get key ${key}`); return Reflect.get(target, key, receiver); } } ); obj.count = 1; // => set key count; obj.count++; // => get key count; // => set key count;
let obj = new Proxy(target, handler)
其中new Proxy
表示生成一個Proxy實例,target
爲須要代理的對象,handler
則是一個對象,定義了各類代理行爲。
若是handler
爲空對象,訪問proxy
與訪問target
效果相同。es6
get
方法用於攔截某個屬性的讀取操做,能夠接受三個參數,依次爲目標對象、屬性名和 proxy 實例自己(嚴格地說,是操做行爲所針對的對象),其中最後一個參數可選。segmentfault
var person = { name: "張三" }; var proxy = new Proxy(person, { get: function(target, property) { if (property in target) { return target[property]; } else { throw new ReferenceError("Property \"" + property + "\" does not exist."); } } }); proxy.name // "張三" proxy.age // 拋出一個錯誤
set
方法用來攔截某個屬性的賦值操做,能夠接受四個參數,依次爲目標對象、屬性名、屬性值和 Proxy 實例自己,其中最後一個參數可選。數組
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'); } } // 對於知足條件的 age 屬性以及其餘屬性,直接保存 obj[prop] = value; } }; let person = new Proxy({}, validator); person.age = 100; person.age // 100 person.age = 'young' // 報錯 person.age = 300 // 報錯
has(target, propKey)
攔截propKey in proxy
的操做,返回一個布爾值。app
deleteProperty(target, propKey)
攔截delete proxy[propKey]
的操做,返回一個布爾值。函數
ownKeys(target)
攔截Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循環,返回一個數組。該方法返回目標對象全部自身的屬性的屬性名,而Object.keys()
的返回結果僅包括目標對象自身的可遍歷屬性。spa
getOwnPropertyDescriptor(target, propKey)
攔截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回屬性的描述對象。雙向綁定
defineProperty(target, propKey, propDesc)
攔截Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一個布爾值。代理
preventExtensions(target)
攔截Object.preventExtensions(proxy)
,返回一個布爾值。
getPrototypeOf(target)
攔截Object.getPrototypeOf(proxy)
,返回一個對象。
isExtensible(target)
攔截Object.isExtensible(proxy)
,返回一個布爾值。
setPrototypeOf(target, proto)
攔截Object.setPrototypeOf(proxy, proto)
,返回一個布爾值。若是目標對象是函數,那麼還有兩種額外操做能夠攔截。
apply(target, object, args)
攔截Proxy
實例做爲函數調用的操做,好比proxy(...args)
、proxy.call(object, ...args
)、proxy.apply(...)
。
construct(target, args)
攔截Proxy
實例做爲構造函數調用的操做,好比new proxy(...args)
。
http://es6.ruanyifeng.com/#do...
Reflect
對象與Proxy
對象同樣,也是 ES6 爲了操做對象而提供的新 API。其目的是:
Object
對象的一些明顯屬於語言內部的方法(好比Object.defineProperty
),放到Reflect
對象上。Object
方法的返回結果,讓其變得更合理。Object
操做都變成函數行爲。Reflec
t對象的方法與Proxy
對象的方法一一對應const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn); const observable = obj => new Proxy(obj, { set }); function set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); queuedObservers.forEach(observer => observer()); return result; } const person = observable({ name: "Amber", age: 18 }); function print() { console.log(`${person.name}, ${person.age}`); } observe(print);