最近更新: 2015-11-09

學習 ECMAScript/JavaScript 6 - Symbol

Symbol (符號) 的基本觀念和用途,我在 Name object 草案 一文說明過。在草案階段稱為 Name object ,正式定案後就給了一個通俗的名稱: Symbol ,正式規範的用法可參考 ES6 In Depth: Symbols

對以 JavaScript 為主要設計語言的程序人員來說,理解 Symbol 時需要把自己對變數與符號的關係認知,提高一級抽象層次。

Symbol()

ECMAScript/JavaScript 6 正式規範中,將 Symbol (符號) 定為第 7 種原生資料型態。當你想要定義一個符號時,可直接調用 Symbol() 配置。嚴格說來,這樣配置的符號是匿名的符號。例如: let sym = Symbol() ,這樣就會讓符號 sym 聯繫一個匿名符號。

Ruby 語言為符號定義了一個簡單的表示語法,只要在名稱前加上 : (冒號)字元,就會建立一個符號。例如 :sym 。在閱讀程式碼時,此一表達方式帶來良好的便利性。

若你在除錯時想印出 sym 的內容時, JavaScript 會告訴你 undefined。 JavaScript 其實是要告訴你 sym 聯繫的匿名符號並未賦值。而這樣的匿名符號也不能賦值。

let sym = Symbol(); // sym 聯繫了另一個 symbol object
console.log(sym);   // undefined
sym = 1;            // 注意,這是賦予另一個值(整數1)給 sym ,而不是賦值給匿名符號。

前述的程式碼的最後一步,將會賦予另一個值給符號 sym ,這將切斷 sym 和一開始的匿名符號的聯繫關係。

如果你在程式中使用了大量的匿名符號,你除錯時會看到一堆 undefined 的變數,這樣很麻煩。為了提高可讀性, ES6 給了符號一個名為 description 的屬性。你只要在調用 Symbol() 時給它一個字串作為參數即可,例如 let sym = Symbol("key1")description 屬性只有兩個用途,一是用在 toString() 時作為字串內容;二是在 console.log() 顯示在除錯訊息中。注意,當你要在字串操作中使用匿名符號時, JavaScript 不會主動轉型為字串。程序人員必須明確地調用 toString() 才行。還有一點, description 輸出時會是 ‘Symbol(description)’ 的樣子。

看看下列的程式碼範例測試一下自己是否理解為什麼最後的結果是 3 和 2 。

let x = Symbol('sym');
let a = {}

a.x = 1;    // using 'x' as public key.
a[x] = 2;   // using a symbol as private key.
a['x'] = 3;

console.log(a.x);   // 3
console.log(a[x]);  // 2

除了最基礎的 Symbol() 外, ES6 正式規範還另外定義了二個符號操作方式。

Symbol.for()

前述的 Symbol() 會配置一個只在定義域(scope)中可用的匿名符號。而 Symbol.for(string) 則會在全域符號表中配置符號,必要的字串參數將成為這個符號在符號表中的鍵。由於有字串鍵可以取得符號,所以不算是匿名符號。這樣的符號可以在不同域中共用。

Symbol.iterator

作為 ES6 iterator (迭代器)的建構方法名稱。

根據 ES6 In Depth: Iterators 的說明,這是牽就 jQuery 而不得不為的語法妥協。因為 jQuery 自訂的迭代器已經使用 ‘iterator’ 作為方法名稱,為了避免和 jQuery 的方法名稱衝突,故 ES6 選擇用 Symbol.iterator 作為 ES6 迭代器的建構方法名稱。

相關文章