Javascript 一共有6種數據類型:Undefined、Null、Number、String、Object、Boolean。今天,咱們先看看第七種:Symbol。api
ES5的對象屬性名都是字符串,這容易形成屬性名的衝突。好比,你使用了一個他人提供的對象,但又想爲這個對象添加新的方法(mixin模式),新方法的名字就有可能與現有方法產生衝突。若是有一種機制,保證每一個屬性的名字都是獨一無二的就行了,這樣就從根本上防止屬性名的衝突。這就是ES6引入Symbol的緣由。跨域
可見,這個類型是提供了一個不可更新的特性,這樣能夠保證別人不會覆蓋你的屬性。下面咱們來看看它的樣子:this
語法:Symbol([description]) let mySymbol = Symbol(); let mySymbol2 = Symbol('this is just a desction');
沒有new,裏面的參數只是一個描述,這就是對這個構造器的最簡單解釋了。debug
當你第一眼看到Symbol,你會在想,什麼鬼,不想用。當你知道它的特性,會讓你不得不重視它。咱們知道,對象的鍵能夠用數字或字符串,但這樣的話就不能保證惟一性,當咱們知道symbol的特性,就能夠拿它來作試驗了。設計
能夠做爲鍵名:code
let mySymbol = Symbol(); let obj = {}; obj[mySymbol] = 'hello';
如此簡單的一句,obj
對象就使用了mySymbol
這個symbol做爲鍵屬性,它是一個symbol,不是一個字符串。你不能用點去訪問它了,相似的,for-in去枚舉一個含有symbol鍵的對象,也不會打印出來(看例子)。既然它的做用就是保證惟一,咱們就能夠在這種需求下知足了。對象
惟一性ip
let a = 'hello'; let b = 'hello'; console.log( a === b); // true let a = Symbol('hello'); let b = Symbol('hello'); console.log( a === b); // false
已有的數據類型,咱們很熟悉。再來看看symbol,即便是同樣的描述,它們也是不相同的。作用域
舉一個例子:文檔
例1
const obj = { [Symbol('age')] : 20, [Symbol('name')] : 'liya', ok: true } for( var i in obj) { console.log(obj[i]); }
運行以後,你只會獲得一個true。for-in 並不能訪問到symbol,想要訪問,你必須用到專用的api。
例2
log.levels = { DEBUG: Symbol('debug'), INFO: Symbol('info'), WARN: Symbol('warn'), }; log(log.levels.DEBUG, 'debug message'); log(log.levels.INFO, 'info message');
咋看也沒有什麼Symbol的事,事實上在ES5時代,你必須這樣寫:
log.levels = { DEBUG: 1, INFO: 2, WARN: 3, };
這樣寫的壞處是,值不是惟一的,某天若是被人把DEBUG的值改爲了3,那你不是頓時懵了。用Symbol的好處在於,你不用理會它的值是什麼,它只是一個佔位符,而且惟一。
每一個symbol是惟一的,即便兩個描述同樣的symbol也不相等。symbol的弱封裝機制:模塊建立了幾個symbol,能夠在任意對象上使用,無須擔憂與其它代碼建立的屬性產生衝突。它只在當前的做用域生效,若是要在全局中共享,就要在全局中註冊,使用Symbol.for()
去註冊。
Symbol('ok'); Symbol.for('ok'); console.log(Symbol('ok') === Symbol('ok')); // false console.log(Symbol.for('ok') === Symbol.for('ok')); // true
第一句和第二句都是建立一個Symbol,不一樣的是,Symbol.for再也不是每次建立不一樣的symbol,它會從註冊表中找,找到了就會返回。不管你訪問幾回,都不會建立新的symbol。全局的symbol能夠跨域和在多個頁面中使用。
查了一些資料,但也不是太過清楚,畢竟用的人還很少。期待在ES6後面可以讓更多人去使用,相似Symbol這種api,你們只是瞄一眼就再也不關注了,除了文檔不夠,更多的是設計上的問題。ES6出了有一段時間,有多少api可以深刻人心,我想只有在坐的各位比較清楚。