什么是 Observer 对象
Observer 是ES7中新增的一个全局对象,它有一个 observe API 可以监听对象,数组,甚至是 DOM 对象的变化。
const obj = {}; Observer.observe(obj, changes => { console.log(changes); });
Observer.observe 方法的参数
Observer.observe 方法的参数有两个,第一个是监听的对象,第二个是回调函数,这个回调函数会在对象发生变化的时候被调用。
回调函数的参数为一个数组,数组内每个元素又是一个对象,这个对象包括了变化前后的值和类型。例如:
const obj = { name: 'foo' }; Observer.observe(obj, changes => { console.log(changes); // 输出 [{type: 'add', name: 'age', oldValue: undefined, newValue: 18}] }); obj.age = 18;
Observer.observe 方法支持的数据类型
Observer.observe 方法不仅支持普通对象,还支持数组和 DOM 对象。
监听数组
const arr = ['foo', 'bar']; Observer.observe(arr, changes => { console.log(changes); // 输出 [{type: 'splice', index: 1, addedCount: 1, removed: ['bar']}] }); arr.splice(1, 1, 'baz');
监听 DOM 对象
<div id="app">Hello World</div>
const app = document.getElementById('app'); Observer.observe(app, changes => { console.log(changes); // 输出 [{type: 'characterData', oldValue: 'Hello World', newValue: 'Hello Observer'}] }); app.firstChild.nodeValue = 'Hello Observer';
Observer.observe 方法不支持的数据类型
由于 Observer.observe 方法是通过 Object.defineProperty 来监听属性的变化,因此它无法监听以下类型:
- Map 和 Set
- WeakMap 和 WeakSet
- Symbol 类型的 key
- 不可配置的属性
如何使用 Observer 对象
Observer对属性的变化的监听非常适合应用于MVVM框架中,可以通过该特性轻松的实现响应式编程。
下面展示了一个vue中响应式编程的实现:
// javascriptcn.com 代码示例 class Dep { constructor() { this.subs = []; } addSub(sub) { this.subs.push(sub); } notify() { this.subs.forEach(sub => sub.update()); } } class Watcher { constructor(vm, key, cb) { this.vm = vm; this.key = key; this.cb = cb; Dep.target = this; vm[key]; Dep.target = null; } update() { this.cb.call(this.vm, this.vm[this.key]); } } function observe(obj) { Object.keys(obj).forEach(key => { let value = obj[key]; const dep = new Dep(); Object.defineProperty(obj, key, { get() { if (Dep.target) { dep.addSub(Dep.target); } return value; }, set(newValue) { if (newValue === value) { return; } value = newValue; dep.notify(); } }); if (typeof value === 'object') { observe(value); } }); return obj; } class Vue { constructor(options) { this._data = observe(options.data); Object.keys(this._data).forEach(key => { Object.defineProperty(this, key, { enumerable: true, configurable: true, get: () => this._data[key], set: newValue => { this._data[key] = newValue; } }); }); } $watch(key, cb) { new Watcher(this, key, cb); } }
使用方式:
// javascriptcn.com 代码示例 const vm = new Vue({ data: { count: 1 } }) vm.$watch('count', () => { console.log('count changed') }) vm.count = 2 // output count changed
总结
Observer 对象是 ES7 中新增的对象,可以用来监听对象,数组和DOM对象的变化,非常适合应用于MVVM框架中。但它并不支持 Map,Set,WeakMap,WeakSet,Symbol类型的 key,以及不可配置的属性。这个功能实现的核心在于 Object.defineProperty 方法。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65419f277d4982a6ebb34376