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 :
上例的 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]」。
相關文章
- 石頭閒語: ECMAScript 6 - Symbol