1. 程式人生 > >原生JavaScript實現觀察者模式

原生JavaScript實現觀察者模式

什麼是觀察者模式

維基百科對觀察者模式的定義如下:

觀察者模式是軟體設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實時事件處理系統。

說的簡單些,就是在資料發生改變時,對應的處理函式自動執行。維基的定義中涉及到了主動發出通知,按照這種方式,在angularJS中的事件廣播更是中規中矩,但是其缺點是程式碼的可維護性較差。那麼如果不進行主動通知,而是在進行物件屬性值設定時,呼叫相關的處理函式,也可達到同等效果。如下見詳細程式碼。

ES5下的實現

在ES5中主要是通過Object.defineProperty

方法定義物件屬性的設定和獲取,並在進行設定時執行相關的處理函式,程式碼示例如下:

// 建立物件
var targetObj = {
    age: 1
}
// 定義值改變時的處理函式
function observer(oldVal, newVal) {
    // 其他處理邏輯...
    console.info('name屬性的值從 '+ oldVal +' 改變為 ' + newVal);
}

// 定義name屬性及其set和get方法
Object.defineProperty(targetObj, 'name', {
    enumerable: true,
    configurable: true
, get: function() { return name; }, set: function(val) { //呼叫處理函式 observer(name, val) name = val; } }); targetObj.name = 'Martin'; targetObj.name = 'Lucas'; console.info('targetObj:', targetObj)

輸出結果為

...
name屬性的值從 Martin 改變為 Lucas
targetObj: {age: 1
, name: 'Lucas'} ...

ES6的實現

使用set方法實現

class TargetObj {
    constructor(age, name) {
        this.name = name;
        this.age = age;
    }
    set name(val) {
        observer(name, val);
        name = val;
    }
}

let targetObj = new TargetObj(1, 'Martin');

// 定義值改變時的處理函式
function observer(oldVal, newVal) {
    // 其他處理邏輯...
    console.info('name屬性的值從 '+ oldVal +' 改變為 ' + newVal);
}
targetObj.name = 'Lucas';
console.info(targetObj)

輸出結果為

...
name屬性的值從 Martin 改變為 Lucas
targetObj: {age: 1, name: 'Lucas'}
...

使用Reflect和Proxy實現

在ES6中新增的Proxy Api用處很多,結合Reflect Api可以方便的實現很多強大的邏輯,詳細介紹可以參見《ECMAScript 6 入門》—— 阮一峰 中的介紹。實現程式碼如下:

class TargetObj {
    constructor(age, name) {
        this.name = name;
        this.age = age;
    }
}

let targetObj = new TargetObj(1, 'Martin');

let observerProxy = new Proxy(targetObj, {
    set(target, property, value, reciever) {
        if (property === 'name') {
            observer(target[property], value);
        }

        Reflect.set(target, property, value, reciever);
    }
});
// 定義值改變時的處理函式
function observer(oldVal, newVal) {
    // 其他處理邏輯...
    console.info(`name屬性的值從 ${oldVal} 改變為 ${newVal}`);
}

observerProxy.name = 'Lucas';
console.info(targetObj);

輸出結果為

...
name屬性的值從 Martin 改變為 Lucas
targetObj: {age: 1, name: 'Lucas'}
...

總結

  1. ES6中很多的新增功能,都有效的提升了JS本身的合理性和高效性
  2. 很多基礎的方法,概念,雖然在做業務實現時使用較少,但是去了解其理念,對編碼思想的影響是很大的
  3. 觀察者模式可以很好的完成資料間的互動行為,雖然已經經常在用,但是具體瞭解後對整體的結構和原理有了更深層次的理解
  4. Proxy真的很好,很強大