JavaScript大師Nicholas C. Zakas又一大作出中文版了

本文節選自Nicholas C. Zakas所著《Understanding EcmaScript6》的中文版《深入理解ES6》,由電子工業出版社出版。
著:【美】Nicholas C. Zakas(尼古拉斯·澤卡斯)
譯:劉振濤
責編:陳秋歌,尋求報道或者投稿請發郵件至chenqg#csdn.net。

導讀:本文節選自圖書《深入理解ES6》第六章,Symbol爲ECMAScript 6引入了第6種原始類型,本文將詳解如何有效地使用它。

在ECMAScript 5及早期版本中,語言包含5種原始類型:字符串型、數字型、布爾型、null和undefined。ECMAScript 6引入了第6種原始類型:Symbol。起初,人們用它來創建對象的私有成員,JavaScript開發者們對這個新特性期待已久。在Symbol出現以前,人們一直通過屬性名來訪問所有屬性,無論屬性名由什麼元素構成,全部通過一個字符串類型的名稱來訪問;私有名稱原本是爲了讓開發者們創建非字符串屬性名稱而設計的,但是一般的技術無法檢測這些屬性的私有名稱。

私有名稱最終演變成了ECMAScript 6中的Symbol,本章將講解如何有效地使用它。雖然通過Symbol可以爲屬性添加非字符串名稱,但是其隱私性就被打破了。最終,新標準中將Symbol屬性與對象中的其他屬性分別分類。

創建Symbol

所有原始值,除了Symbol以外都有各自的字面形式,例如布爾類型的true或數字類型的42。可以通過全局的Symbol函數創建一個Symbol,就像這樣:

letfirstName = Symbol();
let person = {};

person[firstName] = "Nicholas";
console.log(person[firstName]); // "Nicholas"

在上面這段代碼中,創建了一個名爲firstName的Symbol,用它將一個新的屬性賦值給person對象,每當你想訪問這個屬性時一定要用到最初定義的Symbol。記得要合理命名Symbol變量,這樣可以輕鬆區分出它所指代的內容。

注意:由於Symbol是原始值,因此調用new Symbol()會導致程序拋出錯誤。也可以執行new Object(你的Symbol)創建一個Symbol的實例,但目前尚不清楚這個功能何時可以使用。

Symbol函數接受一個可選參數,其可以讓你添加一段文本描述即將創建的Symbol,這段描述不可用於屬性訪問,但是建議你在每次創建Symbol時都添加這樣一段描述,以便於閱讀代碼和調試Symbol程序。

let firstName = Symbol("first name");
let person = {};

person[firstName] = "Nicholas";

console.log("first name" in person); // false
console.log(person[firstName]); // "Nicholas"
console.log(firstName); // "Symbol(first name)"

Symbol的描述被存儲在內部的[[Description]]屬性中,只有當調用Symbol的toString()方法時纔可以讀取這個屬性。在執行console.log()時隱式調用了firstName的toString()方法,所以它的描述會被打印到日誌中,但不能直接在代碼裏訪問[[Description]]。

Symbol的辨識方法

Symbol是原始值,且ECMAScript 6同時擴展了typeof操作符,支持返回”Symbol”,所以可以用typeof來檢測變量是否爲Symbol類型。

let symbol = Symbol("test symbol");
console.log(typeof symbol); // "symbol"

通過其他間接方式也可以檢測變量是否爲Symbol類型,但是typeof操作符是最準確也是你最應首選的檢測方式。

Symbol的使用方法

所有使用可計算屬性名的地方,都可以使用Symbol。前面我們看到的都是在括號中使用Symbol,事實上,Symbol也可以用於可計算對象字面量屬性名、Object.defineProperty()方法和Object.defineProperties()方法的調用過程中。

letfirstName = Symbol("first name");

// 使用一個可計算對象字面量屬性
let person = {
[firstName]: "Nicholas"
};

// 將屬性設置爲只讀
Object.defineProperty(person, firstName, { writable: false });

letlastName = Symbol("last name");

Object.defineProperties(person, {
[lastName]: {
value: "Zakas",
writable: false
}
});

console.log(person[firstName]); // "Nicholas"
console.log(person[lastName]); // "Zakas"

在此示例中,首先通過可計算對象字面量屬性語法爲person對象創建了一個Symbol屬性firstName。後面一行代碼將這個屬性設置爲只讀。隨後,通過Object.defineProperties()方法創建一個只讀的Symbol屬性lastName,此處再次使用了對象字面量屬性,但卻是作爲Object.defineProperties()方法的第二個參數使用。

儘管在所有使用可計算屬性名的地方,都可以使用Symbol來代替,但是爲了在不同代碼片段間有效地共享這些Symbol,需要建立一個體系。

Symbol共享體系

有時我們可能希望在不同的代碼中共享同一個Symbol,例如,在你的應用中有兩種不同的對象類型,但是你希望它們使用同一個Symbol屬性來表示一個獨特的標識符。一般而言,在很大的代碼庫中或跨文件追蹤Symbol非常困難而且容易出錯,出於這些原因,ECMAScript 6提供了一個可以隨時訪問的全局Symbol註冊表。

如果想創建一個可共享的Symbol,要使用Symbol.for()方法。它只接受一個參數,也就是即將創建的Symbol的字符串標識符,這個參數同樣也被用作Symbol的描述,就像這樣:

letuid = Symbol.for("uid");
let object = {};

object[uid] = "12345";

console.log(object[uid]); // "12345"
console.log(uid); // "Symbol(uid)"

Symbol.for()方法首先在全局Symbol註冊表中搜索鍵爲”uid”的Symbol是否存在,如果存在,直接返回已有的Symbol;否則,創建一個新的Symbol,並使用這個鍵在Symbol全局註冊表中註冊,隨即返回新創建的Symbol。
後續如果再傳入同樣的鍵調用Symbol.for()會返回相同的Symbol,像這樣:

letuid = Symbol.for("uid");
let object = {
[uid]: "12345"
};

console.log(object[uid]); // "12345"
console.log(uid); // "Symbol(uid)"

let uid2 = Symbol.for("uid");

console.log(uid === uid2); // true
console.log(object[uid2]); // "12345"
console.log(uid2); // "Symbol(uid)"

在這個示例中,uid和uid2包含相同的Symbol並且可以互換使用。第一次調用Symbol.for()方法創建這個Symbol,第二次調用可以直接從Symbol的全局註冊表中檢索到這個Symbol。

還有一個與Symbol共享有關的特性:可以使用Symbol.keyFor()方法在Symbol全局註冊表中檢索與Symbol有關的鍵。舉個例子:

letuid = Symbol.for("uid");
console.log(Symbol.keyFor(uid)); // "uid"

let uid2 = Symbol.for("uid");
console.log(Symbol.keyFor(uid2)); // "uid"

let uid3 = Symbol("uid");
console.log(Symbol.keyFor(uid3)); // undefined

注意,uid和uid2都返回了”uid”這個鍵,而在Symbol全局註冊表中不存在uid3這個Symbol,也就是不存在與之有關的鍵,所以最終返回undefined。

特別提醒:Symbol全局註冊表是一個類似全局作用域的共享環境,也就是說你不能假設目前環境中存在哪些鍵。當使用第三方組件時,儘量使用Symbol鍵的命名空間以減少命名衝突。舉個例子,jQuery的代碼可以爲所有鍵添加”jquery”前綴,就像”jquery.element”或其他類似的鍵。

點擊訂購:深入理解ES6

圖片描述


歡迎加入“CSDN前端開發者”羣,與更多專家、技術同行進行熱點、難點技術交流。請掃描以下二維碼申請入羣。
圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章