?
系列文章 -- ES6筆記系列
?
Symbol是什么?中文意思是標志、記號,顧名思義,它可以用了做記號。
是的,它是一種標記的方法,被ES6引入作為一種新的數據類型,表示獨一無二的值。
由此,JS的數據類型多了一位成員:
Number、String、Boolean、undefined、Object、Symbol
?
一、簡單使用
1. 聲明
類似字符串String的聲明方式 var str = 'str'; Symbol的聲明方式類似,它調用構造函數Symbol()
var s = Symbol(); typeof s // symbol
2. 使用
Symbol聲明了是為了使用
var s = Symbol(); var s1 = Symbol();console.log(s, s1);
console.log(s == s1); // false
Chrome的輸出中自動對Symbol類型的數據做了標識處理,由輸出知道,雖然通過Symbol生成的兩個標志不相同,但兩個變量混淆了分不清。
實際上,為了區別出不同的symbol,我們可以在參數中指定
var s = Symbol('s'); var s1 = Symbol('s1');console.log(s, s1);
symbol除了簡單的在控制臺輸出之外,還可以參與到其他代碼邏輯運算中去,最常見的是在對象屬性名稱中(為確保屬性名惟一而存在)
var s = Symbol(); var s1 = Symbol('s1');var obj = {[s]: function() {console.log(1);},[Symbol()]: () => {console.log(2);},[s1]: 3 };obj[s]() // 1 obj[s1] // 3
注意到symbol要使用[]中括號包裹起來,調用的時候也一樣(不能使用obj.s的方式,這樣會被識別成字符串)
3. 屬性的遍歷
如上代碼,如果我們想遍歷對象的屬性值,也許會這樣操作
for (var item in obj) {if (typeof obj[item] === 'function') {obj[item]();} else {console.log(obj[item]);} }Object.keys(obj).forEach(function(item) {if (typeof obj[item] === 'function') {obj[item]();} else {console.log(obj[item]);} });
卻發現什么也沒輸出
因為要獲取到Symbol這個屬性名,ES6引入了新的方法,舊的for...in ?Object.keys()、Object.getOwnPropertyNames()等不支持訪問
使用新的getOwnPropertySymbols方法
var s = Symbol(); var s1 = Symbol('s1');var obj = {[s]: function() {console.log(1);},[Symbol()]: () => {console.log(2);},[s1]: 3,a: 4 };Object.getOwnPropertySymbols(obj).forEach(function(item) {if (typeof obj[item] === 'function') {obj[item]();} else {console.log(obj[item]);} });// 輸出 1 2 3
雖然識別了symbol類屬性,但常規屬性卻被忽略了,所以ES6還引入了一個新的內置類Reflect,它的ownKeys方法可以識別出所有屬性名
var s = Symbol(); var s1 = Symbol('s1');var obj = {[s]: function() {console.log(1);},[Symbol()]: () => {console.log(2);},[s1]: 3,a: 4 };Reflect.ownKeys(obj).forEach(function(item) {if (typeof obj[item] === 'function') {obj[item]();} else {console.log(obj[item]);} });// 輸出 4 1 2 3
?
4. 類型轉換
數字轉換成字符串我們可以簡單的使用 + '' 實現,symbol呢
var s = Symbol(); var s1 = Symbol('s1');s + '' // Uncaught TypeError: Cannot convert a Symbol value to a string
出錯了,提示不能轉換。
實際上,我們只是不能直接轉換值,還是可以用toString或String方法轉換這個標志的
var s = Symbol(); var s1 = Symbol('s1');s.toString() // Symbol() String(s1) // Symbol(s1)
類似的,也可以轉換為bool值
var s = Symbol(); var s1 = Symbol('s1');!!s // true !s // false Boolean(s1) // true
不過,symbol是不能轉換成數值Number類型的
5. Symbol.for()相同值的使用
有時候我們需要使用同一個symbol值,而調用Symbol()的時候會自動創建不同的值
var temp = [];var scores = [{name: 'jack',score: 10 }, {name: 'pick',score: 20 }, {name: 'pick',score: 30 }];scores.forEach(function(item) {temp.push({name: Symbol(item.name),score: item.score}); });temp[1].name == temp[2].name // false
以上代碼主要為了登記不同用戶的分數,并確保唯一性使用了symbol,但最終用戶名都為pick的項不想等,可能會導致后續的計算出錯
把Symbol換成Symbol.for,輸出才為true
兩者類似,都可以生成一個Symbol類型的值,但后者是先判斷全局中是否有該symbol值,有就返回該值,沒有才創建,并將該值登記在全局中
var s = Symbol.for('s'); var s1 = Symbol.for('s');s == s1 // true s === s1 // truevar s = Symbol('s'); var s1 = Symbol('s');s == s1 // false s === s1 // false
此外,我們可以用Symbol.keyFor()訪問全局中的symbol相關項,沒有則返回undefined
var s = Symbol.for('s'); var s1 = Symbol.for('s');Symbol.keyFor(s) // s Symbol.keyFor(s1) // s Symbol.keyFor(s2) // Uncaught ReferenceError: s2 is not definedvar s3 = Symbol('s3'); Symbol.keyFor(s3) // undefined
?
6. Symbol的更多使用
Symbol的更多使用方法,可參考 MDN - Symbol