DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> JavaScript基礎知識 >> 你的 mixin 真的兼容 ECMAScript 5 嗎?
你的 mixin 真的兼容 ECMAScript 5 嗎?
編輯:JavaScript基礎知識     

我最近在與客戶合作的項目中,需要充分利用的 ECMAScript 5,在此我遇到一個非常有趣的問題。 該問題源於一個非常常見的模式: mixin , 也就是在 JavaScript 中把一個對象的屬性或者方法 mixin 到另一個。

大多數 mixin 的功能看起來像這樣:

復制代碼 代碼如下:
function mixin(receiver, supplier) {
    for (var property in supplier) {
        if (supplier.hasOwnProperty(property)) {
            receiver[property] = supplier[property];
        }
    }
}

在此 mixin() 函數中,一個 for 循環遍歷 supplier 對象的屬性並賦值給 receiver 對象。 幾乎所有的 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

這個例子看起來有點做作,但它准確的描述這個問題。 進行 mixin 的屬性使用了 ECMAScript 5 的新特性:一個 getter 屬性存取器。 getter 引用一個未初始化的局部變量 name,因此這個屬性未定義 undefined。

後來,name 被分配了一個值,以便使存取器 getter 可以返回一個有效的值。 不幸的是,object.name(被 mixin 的屬性)始終返回 undefined。

這是怎麼回事呢?

我們仔細分析 mixin() 函數。 事實上,在循環語句中,並沒有把屬性從一個對象重新賦值給到另一個對象。 它實際上是創建一個同名的屬性,並把 supplier 對象的存取器方法 getter 的返回值賦值給了它。 (譯注:目標對象得到的不是 getter 這個方法,而是得到了 getter 方法的返回值。@justjavac)

在這個例子中,mixin() 的過程其實是這樣的:

復制代碼 代碼如下:
receiver.name = supplier.name;

屬性 receiver.name 被創建,並且被賦值為 supplier.name 的值。 當然,supplier.name 有一個 getter 方法用來返回本地變量 name 的值。 此時,name 的值為 undefined,所以 receiver.name 存儲的是 值。 並沒有為 receiver.name 創建一個 getter 方法,因此它的值永遠不會改變。

要解決這個問題,你需要使用屬性描述符(譯注:descriptor)將屬性從一個對象 mixin 到另一個對象。 一個純粹的 ECMAScript 5 版本的 mixin() 應該這樣寫:

復制代碼 代碼如下:
function mixin(receiver, supplier) {

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

在這個新版本函數中,Object.keys() 用來獲取一個數組,包含了 supplier 對象的所有枚舉屬性。 然後,foreach() 方法用來遍歷這些屬性。 調用 Object.getOwnPropertyDescriptor() 方法獲取 supplier 對象的每個屬性描述符(descriptor)。

由於描述符(descriptor)包含了所有的屬性信息,包括 getter 和 setter 方法, 該描述符(descriptor)可以直接傳遞給 Object.defineProperty() ,用來在 receiver 對象上創建相同的屬性。 使用這個新版本的 mixin() ,可以解決前面遇到的問題,從而得到你所期望的結果。 getter 方法被正確地從 supplier 傳遞到了 receiver。

當然,如果你仍然需要支持舊的浏覽器,那麼你就需要一個函數,回落的 ECMAScript 3:

復制代碼 代碼如下:
function mixin(receiver, supplier) {
    if (Object.keys) {
        Object.keys(supplier).forEach(function(value, 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 方法。 否則,你會發現自己陷入像我一樣的錯誤。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved