JavaScript >> Javascript 文檔 >  >> JavaScript

你的 mixins 兼容 ECMAScript 5 嗎?

最近,我正在與一位客戶合作,在一個可以充分利用 ECMAScript 5 的項目上遇到一個有趣的問題。問題源於使用 mixins,這是 JavaScript 中一種非常常見的模式,其中一個對像從另一個對象分配屬性(包括方法)。大多數mixin函數看起來像這樣:

function mixin(receiver, supplier) {
    for (var property in supplier) {
        if (supplier.hasOwnProperty(property)) {
            receiver[property] = supplier[property];
        }
    }
}

mixin() 內部 函數,一個 for 循環遍歷供應商自己的所有屬性,並將值分配給接收器上的同名屬性。幾乎每個 JavaScript 庫都有某種形式的這個函數,讓你可以編寫如下代碼:

mixin(object, {

    name: "Nicholas",

    sayName: function() {
        console.log(this.name);
    }

});

object.sayName();       // outputs "Nicholas"

在本例中,object 接收屬性 name 和方法 sayName() .這在 ECMAScript 3 中很好,但並未涵蓋 ECMAScript 5 中的所有基礎。

我遇到的問題是這種模式:

(function() {

    // to be filled in later
    var name;

    mixin(object, {

        get name() {
            return name;
        }

    });

    // let's just say this is later
    name = "Nicholas";

}());

console.log(object.name);       // undefined

這個例子看起來有點做作,但卻是對問題的準確描述。要混入的屬性包括只有一個 getter 的 ECMAScript 5 訪問器屬性。該 getter 引用了一個名為 name 的局部變量 未初始化為變量,因此接收 undefined 的值 .稍後,name 被分配一個值,以便訪問者可以返回一個有效值。不幸的是,object.name (混合屬性)總是返回 undefined .這是怎麼回事?

仔細查看 mixin() 功能。實際上,循環並不是將屬性從一個對象重新分配給另一個對象。它實際上是創建一個具有給定名稱的數據屬性,並通過訪問供應商上的該屬性為其分配返回值。對於此示例,mixin() 有效地做到了這一點:

receiver.name = supplier.name;

數據屬性 receiver.name 被創建並賦值為 supplier.name .當然,supplier.name 有一個返回本地 name 值的 getter 多變的。在那個時間點,name 值為 undefined , 所以這是存儲在 receiver.name 中的值 .沒有為 receiver.name 創建每個 getter 所以值永遠不會改變。

要解決此問題,您需要使用屬性描述符將屬性從一個對象正確混合到另一個對象。 mixin() 的純 ECMAScript 5 版本 應該是:

function mixin(receiver, supplier) {

    Object.keys(supplier).forEach(function(property) {
        Object.defineProperty(receiver, property, Object.getOwnPropertyDescriptor(supplier, property));
    });
}

在這個新版本的函數中,Object.keys() 用於檢索 supplier 上所有可枚舉屬性的數組 .然後,forEach() 方法用於迭代這些屬性。對 Object.getOwnPropertyDescriptor() 的調用 檢索 supplier 的每個屬性的描述符 .由於描述符包含有關屬性的所有相關信息,包括 getter 和 setter,因此該描述符可以直接傳遞到 Object.defineProperty()receiver 上創建相同的屬性 .使用這個新版本的 mixin() ,這篇文章前面的有問題的模式正如你所期望的那樣工作。吸氣劑被正確轉移到 receiver 來自 supplier .

當然,如果您仍然需要支持舊版瀏覽器,那麼您將需要一個回退到 ECMAScript 3 方式的函數:

function mixin(receiver, supplier) {
    if (Object.keys) {
        Object.keys(supplier).forEach(function(property) {
            Object.defineProperty(receiver, property, Object.getOwnPropertyDescriptor(supplier, property));
        });
    } else {
        for (var property in supplier) {
            if (supplier.hasOwnProperty(property)) {
                receiver[property] = supplier[property];
            }
        }
    }
}

如果您使用的是 mixin() 函數,請務必仔細檢查它是否適用於 ECMAScript 5,特別是適用於 getter 和 setter。否則,你可能會發現自己像我一樣遇到錯誤。

更新(2012 年 12 月 12 日) :修正編碼錯誤。


Tutorial JavaScript 教程
  1. Javascript中的文本格式

  2. 開玩笑、反應和模擬

  3. Reduc Storage Web Console v0.4.0 已經發布

  4. 微軟推出新的 UI 庫

  5. Paper JS - 開源 HTML5 動畫框架

  6. 按鈕不能作為按鈕的後代出現

  7. Javascript是編譯語言嗎?

  1. 實現 DOM contains() 方法

  2. 節點模塊導出解釋 – 使用 JavaScript 導出函數示例

  3. 4 門免費 MongoDB 課程

  4. V8 會自動緩存編譯的正則表達式嗎?

  5. next-export-i18n v1.4.0:使用戶默認語言可選

  6. 一種簡單有效的人群模擬引導系統

  7. 一種全新的 JavaScript 調試器(Dbux:為什麼?什麼?)

  1. 艱難地製作一個更好看的網站

  2. 堅實的原則

  3. 🌟🆓 我們最喜歡的 2019 年學習 Web 開發的免費資源

  4. 建立一個 NFT 鑄幣平台,用 Bunzz 鑄幣自拍。