最近更新: 2012-06-28

ECMAScript6 草案的 Name object

JavaScript 的下一版規格 ECMAScript6 提出了 Name object 的規範。 這是一種少見的語言功能。 由於這個功能值得玩味,所以我寫了這篇文章。

在介紹 Name object 之前,我們最好再次複習變數與變數名稱的關係: 當我們使用變數 a 的時候,其意義是使用符號 a 所指涉的那個變數,而不是符號 a 本身。

這句是抽象敘述,具體而言可藉車與車牌為喻,以便理解。

這裡有一輛車,這是一個實際存在的個體。車上又掛有一塊車牌,車牌上寫著車號 a 。 在程式語言中,當我想發動那輛車時,我不能寫著「發動那輛車」這種敘述。 那是日常對話時配合肢體動作用的口語,就算在書面文中也是模糊不清的敘述,在程式語言中更不能被電腦理解。 程式語言必須寫成「令掛著車牌 a 的車輛發動」。如下:

var a = new Car();

a.launch();

其實 var a = new Car(); 這一行看似簡單的敘述,就包含了三個行為。 一、配置符號 a;二、配置一個類型為 Car 的變數;三、指定符號 a 聯繫第二步配置的變數。 白話說就是:一、做一塊車牌寫著 a ;二、造一輛車;三、將車牌掛到車上。

當你看完上一段敘述時,你就應該意識到 var a = new Car(); 實質上產生了兩個個體。 一個是車牌(符號),另一個是車。

但是大部份的程式語言並不讓程序人員操作符號,只讓我們動符號指涉的對象。 亦即程序人員操作的將是掛著車牌 a 的車輛(符號 a 指涉的對象),而不是車牌(符號本身)。

複習上述的基本觀念之後,再看 ECMAScript6 提出的 Name object 就不是那麼難懂了。 Name object 就是一個單純表達符號的個體 (Ruby 也有這種功能)。

將 Name object 應用到屬性上,就可以在 JavaScript 中實現私有(非公開)屬性了。 例如 example.js :

import Name from "@name"

let key = new Name();
// 產生一個符號。在程式語言中,每個符號都是獨一無二的。

function MyClass(privateData, publicData) {
    // 1. 以 Name object 為屬性名稱。
    this[key] = privateData;

    // 2. 以 String object 為屬性名稱。
    this["key"] = publicData;
    // 與 this.key = public Data; 同義

    // 3. Lost property.
    this[new Name()] = "Even you can't touch this property.";
}

上例的 let key = new Name(); 產生了一個獨一無二的新符號,再將符號 key 聯繫這個新符號,並用它作為 MyClass 的其中一個屬性的名稱。 在其他模組中,你無法得到這個符號。所以其他模組就無法透過符號直接存取這個屬性,也就實現了私有屬性的功能。

至於 JavaScript 的屬性連結子(.),在 JavaScript 內部實際上是以字串為鍵的索引操作。 故 this.key 在 JavaScript 內部其實是 this["key"]。 這也阻絕了外界操作 this[key] 屬性的意圖。

此外,ECMAScript6 說明以 Name object 為名稱的屬性,其可枚舉性(enumerability attribute)預設為 false 。 故一般慣用的反射方式,如 getOwnPropertyNames()for...in 皆不會列出這種屬性。

更多相關資訊,請詳閱「harmony:private_name_objects [ES Wiki]」。

相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/19752888.html