Observer Pattern(观察者模式)
Observer Pattern 其实很常遇到,许多API 的设计上都用了Observer Pattern,最简单的例子就是DOM 物件的事件监听:
function clickHandler(event) { console.log('user click!'); } document.body.addEventListener('click', clickHandler)
观察者模式:我们可以对某件事注册监听,并在事件发生时,自动执行我们注册的监听者(listener)。
Es5版本:
function Producer() { // 这个 if 只是避免使用者不小心把 Producer 当做函数调用 if(!(this instanceof Producer)) { throw new Error('请用 new Producer()!'); } this.listeners = []; } // 加入监听的方法 Producer.prototype.addListener = function(listener) { if(typeof listener === 'function') { this.listeners.push(listener) } else { throw new Error('listener 必须是 function') } } // 移除监听的方法 Producer.prototype.removeListener = function(listener) { this.listeners.splice(this.listeners.indexOf(listener), 1) } // 发送通知的方法 Producer.prototype.notify = function(message) { this.listeners.forEach(listener => { listener(message); }) }
es6 版本
class Producer { constructor() { this.listeners = []; } addListener(listener) { if(typeof listener === 'function') { this.listeners.push(listener) } else { throw new Error('listener 必须是 function') } } removeListener(listener) { this.listeners.splice(this.listeners.indexOf(listener), 1) } notify(message) { this.listeners.forEach(listener => { listener(message); }) } }
调用例子:
var egghead = new Producer(); function listener1(message) { console.log(message + 'from listener1'); } function listener2(message) { console.log(message + 'from listener2'); } egghead.addListener(listener1);egghead.addListener(listener2); egghead.notify('A new course!!')
/**
输出:
a new course!! from listener1
a new course!! from listener2
**/
Iterator Pattern (迭代器模式)
var arr = [1, 2, 3]; var iterator = arr[Symbol.iterator](); iterator.next(); // { value: 1, done: false } iterator.next(); // { value: 2, done: false } iterator.next(); // { value: 3, done: false } iterator.next(); // { value: undefined, done: true }
简单实现:
es5: function IteratorFromArray(arr) { if(!(this instanceof IteratorFromArray)) { throw new Error('请用 new IteratorFromArray()!'); } this._array = arr; this._cursor = 0; } IteratorFromArray.prototype.next = function() { return this._cursor < this._array.length ? { value: this._array[this._cursor++], done: false } : { done: true }; } es6: class IteratorFromArray { constructor(arr) { this._array = arr; this._cursor = 0; } next() { return this._cursor < this._array.length ? { value: this._array[this._cursor++], done: false } : { done: true }; } }
优势
- Iterator的特性可以拿来做延迟运算(Lazy evaluation),让我们能用它来处理大数组。
- 第二因为iterator 本身是序列,所以可以第调用方法像map, filter... 等!
延迟运算(Lazy evaluation)
function* getNumbers(words) { for (let word of words) { if (/^[0-9]+$/.test(word)) { yield parseInt(word, 10); } } } const iterator = getNumbers('30 天精通 RxJS (04)'); iterator.next(); // { value: 3, done: false } iterator.next(); // { value: 0, done: false } iterator.next(); // { value: 0, done: false } iterator.next(); // { value: 4, done: false } iterator.next(); // { value: undefined, done: true }
把一个字串丢进getNumbersh函数时,并没有马上运算出字串中的所有数字,必须等到我们执行next()时,才会真的做运算,这就是所谓的延迟运算(evaluation strategy)
选自
https://segmentfault.com/a/1190000013141856