ES6躬行記(6)——Symbol
本節將會重點分析ES6引入的第6種基本類型:Symbol(符號)。符號可以像字元串那樣作為對象的屬性名,只是它有唯一性的特點,可以避免屬性名之間的衝突。
一、創建
符號沒有字面量形式,只能通過Symbol()函數創建。該函數有一個可選的參數,只是用來描述當前符號,除了便於閱讀之外,沒有其他用途。由此可知,即使兩個符號的描述相同,它們還是不能畫等號。注意,Symbol()不是構造函數,因此不能和new運算符組合使用,否則會拋出類型錯誤。下面用一個例子展示符號的創建。
var sym1 = Symbol(),
sym2 = Symbol("name"),
sym3 = Symbol("name"),
sym4 = new Symbol(); //拋出類型錯誤
console.log(sym2 === sym3); //false
如果要識別一個變數是否為符號,可以用typeof運算符。ES6擴展了它,當檢測到符號時,能返回一個新的類型字元串「symbol」,具體如下所示。
typeof sym1; //"symbol"
typeof sym2; //"symbol"
二、類型轉換
符號在類型轉換時表現得並不靈活,它無法與數字或字元串進行運算,也無法顯式的轉換成數字。如下所示,後面四條語句在執行時都會報錯。
var sym = Symbol("age");
Number(sym);
parseInt(sym);
1 + sym;
"" + sym;
不過,符號可以顯式的轉換成字元串或布爾值,具體如下所示。
Boolean(sym); //true
!sym; //false
sym.toString(); //"Symbol(age)"
String(sym); //"Symbol(age)"
三、全局共享
ES6會在內部維護一張全局符號註冊表,通過Symbol.for()方法,可以登記指定符號,使其變成一個全局有效地符號,從而達到全局共享。該方法只接收一個參數,這個參數既是註冊表中的鍵值,同時也是此符號的描述。下面的代碼調用了兩次Symbol.for()方法,傳遞了相同的參數,返回的卻是同一個全局符號。
var sym1 = Symbol.for("name"),
sym2 = Symbol.for("name");
console.log(sym1 === sym2); //true
在上面的代碼中,第一次調用Symbol.for()方法時,會在註冊表中搜索鍵值為「name」的符號,由於沒有找到,所以就會創建一個新的符號。而在第二次調用Symbol.for()方法時,由於傳遞的鍵值與前一次相同,因此會返回剛剛的那個符號。從而可知,對變數sym1和sym2進行全等比較,返回的結果將是true。
如果要獲取某個全局符號所對應的鍵值(即它的描述),那麼可以通過Symbol.keyFor()實現,具體操作如下所示。
Symbol.keyFor(sym1); //"name"
Symbol.keyFor(sym2); //"name"
四、屬性名
本節開頭曾提到過對象的屬性名可以用符號表示,而這類屬性可以有三種賦值方式。第一種是用方括弧,注意,不能用點號,因為點號後面的標識符會被識別成字元串而不是符號。下面代碼分別用方括弧和點號為obj對象的sym屬性賦值,前者被識別成了符號屬性,而後者卻被識別成了字元串屬性。
var sym = Symbol("name"),
obj = {};
obj[sym] = "strick";
obj.sym = "strick";
console.log(obj); //{Symbol(name): "strick", sym: "strick"}
第二種是在創建對象字面量時,用計算屬性名的方式(即屬性名被方括弧包裹)為其賦值,如下所示。
obj = {
[sym]: "freedom"
};
第三種是調用Object.defineProperty()或Object.defineProperties()方法來為符號屬性賦值,如下所示。
Object.defineProperty(obj, sym, { value: "justice" });
注意,符號屬性是不可枚舉的,既不能被for-in等循環遍歷到,也不能被Object.keys()、Object.getOwnPropertyNames()等方法讀取到。但可以通過Object.getOwnPropertySymbols()方法獲得對象的符號屬性,具體如下所示。
obj = {
[sym]: "freedom",
age: 28
};
Object.keys(obj); //["age"]
Object.getOwnPropertyNames(obj); //["age"]
Object.getOwnPropertySymbols(obj); //[Symbol(name)]
五、內置符號
ES6提供了一些內置符號,也叫做知名符號(Well-Known Symbol)。它們暴露了語言的內部邏輯,允許開發人員修改或拓展規範所描述的對象特徵或行為。每一個內置符號對應Symbol對象的一個屬性,例如Symbol.hasInstance、Symbol.iterator等,表1列出了11個內置符號。