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);