先簡單說說什麼是Symbol
- Symbol是ES6新增的基礎數據類型,它的特色就是獨一無二的,如同UUID同樣;
- Symbol是函數,經過調用Symbol函數來建立Symbol數據;
- Symbol仍是內置對象,提供一系列函數well-known Symbol方法來改變JS語言的內部行爲;
Symbol的特性與使用
示例:建立Symbol數據
- Symbol沒有字面量的建立方式,也不能以
new Symbol()
構造函數的方式建立,只能經過調用Symbol([description])
函數,或者Symbol.for()
來建立。
new Symbol()
let symbol1 = Symbol()
let localSymbol Symbol('desc1')
let globalSymbol = Symbol.for('desc1')
console.log(localSymbol === globalSymbol)
複製代碼
特性:Symbol老是惟一的
- 數據老是獨一無二的,不只在函數、模塊甚至在window頂層做用域中都是惟一的
let f1 = Symbol('flag')
let f2 = Symbol('flag')
console.log(f1,f2)
console.log(f1 === f2)
console.log(f1 === 'flag')
let lock = Symbol.for('flag')
let lockFlag = Symbol.for('flag')
console.log(lock === lockFlag)
console.log(f1 === lock)
console.log(Symbol.keyFor('flag'))
console.log(Symbol.keyFor('test'))
複製代碼
示例:使用Symbol來定義常量
- 既然Symbol的特性是惟一標誌,咱們能夠用Symbol來作常量。
- 之前咱們定義常量是這樣嬸的:
const FRUIT = {
APPLE: 'APPLE',
BANANA: 'BANANA',
STRAWBERRY: 'STRAWBERRY'
}
console.log(FRUIT.APPLE)
const FRUIT = {
APPLE: 'APPLE',
BANANA: 'BANANA',
STRAWBERRY: 'STRAWBERRY',
PINEAPPLE: 'APPLE'
}
const FRUIT = {
APPLE: Symbol(),
BANANA: Symbol(),
STRAWBERRY: Symbol()
}
function translate(FRUIT_TYPE){
switch (FRUIT_TYPE) {
case FRUIT.APPLE:
console.log('蘋果')
break;
case FRUIT.BANANA:
console.log('香蕉')
break;
case FRUIT.STRAWBERRY:
console.log('草莓')
break;
default:
console.log('未匹配')
break;
}
}
translate(FRUIT.APPLE)
複製代碼
示例:使用Symbol來定義人名
- 好比一個班級裏面,想經過人名來做爲惟一標識,但人名又沒辦法避免重複,經過Symbol來實現
const grade = {
[Symbol('Lily')]: {
address: 'shenzhen',
tel: '186******78'
},
[Symbol('Annie')]: {
address: 'guangzhou',
tel: '183******12'
},
[Symbol('Lily')]: {
address: 'beijing',
tel: '172******10'
},
}
複製代碼
特性:Symbol的類型判斷和類型轉換
- 和String類型同樣,Symbol類型能夠經過
typeof
操做符進行類型判斷
let symbol = Symbol()
console.log(typeof Symbol)
複製代碼
- 但和String類型不同的是,Symbol不會進行隱式的自動類型轉換,因此不能直接進行字符串拼接運算和算術運算。但能夠人爲的進行顯式類型轉換,好比轉成String、Boolean、Number、Object
let symbolUUID = Symbol('uuid')
console.log(symbolUUID + '測試')
console.log(symbolUUID + 1)
console.log(symbolUUID ? '真' : '假')
console.log(String(symbolUUID) + '測試')
複製代碼
特性:Symbol可做爲對象的屬性key名
- 根據規範,Symbol類型能夠做爲數據單獨存在,也能夠做爲對象的屬性key名。而且,對象的屬性key只能是字符串類型或者Symbol類型,沒有別的數據類型能夠做爲屬性key,Boolean不行,Number也不行。
- 但值得注意的是,須要以
{[SymbolKey]: value}
數組括弧的方式來掛載。
let desc = Symbol('desc')
let person = {
name: 'huilin',
sex: '男',
[desc]: '職位:前端工程師'
}
console.log(person)
複製代碼
console.log(JSON.stringify(person))
for(key in person){
console.log(key)
}
console.log(Object.keys(person))
console.log(Object.getOwnPropertyNames(person))
console.log(Object.getOwnPropertySymbol(person))
console.log(Reflect.ownKeys(person))
複製代碼
示例:經過Symbol模擬對象的私有屬性或者私有方法
const id = Symbol()
class User {
constructor(idVal, name, age){
this[id] = idVal
this.name = name
this.age = age
}
checkId(id){
return this[id] === id
}
}
let u = new User('001', 'Jay', 40)
console.log(u.name, u.age, u[id])
console.log(u.checkId('001'))
console.log(u.checkId('002'))
複製代碼
示例:利用Symbol進行數據歸集和整合
- 拿張鑫旭大佬打聽小美眉的例子來看,一般狀況下兩個對象合併,key相同則會覆蓋:
let info1 = {
name: '小雪',
age: 24,
job: '前端工程師',
desc: '喜歡看電影,已經有交往對象'
}
let info2 = {
desc: '喜歡小狗,住在南山區,上下班坐公交車'
}
console.log(Object.assgin(info1,info2))
複製代碼
- 那改爲用Symbol做爲屬性key名會怎樣呢?Symbol不會進行覆蓋的
let info1 = {
name: '小雪',
age: 24,
job: '前端工程師',
[Symbol('desc')]: '喜歡看電影,已經有交往對象'
}
let info2 = {
[Symbol('desc')]: '喜歡小狗,住在南山區,上下班坐公交車'
}
console.log(Object.assgin(info1,info2))
複製代碼
- 可見,Symbol更關注的是value值,而不是key名。能夠思考得出,Symbol的特性就是方便對數據進行歸集和整合。
- 拿現實中的例子來講吧,微信文章的點贊牆,數據值都是點贊,但記錄不會被覆蓋,用戶的頭像都會羅列出來;再好比簽到簿,數據值是時間,頗有多是扎堆簽到時間同樣,但也不會被覆蓋,而是把記錄羅列進來。
- 再回到JavaScript語法層面,可能你們會以爲,名字衝突這種事情,機率很低吧?有必要專門新增一個Symbol嘛?可是你想啊,ES6的Module,導入導出是能夠起別名的;還有ES6的解構,能夠直接獲取對象的屬性名到當前環境;這樣你還以爲名字衝突的機率低嗎?
- 因此Symbol經過歸集和整合的特性,針對基礎框架版本升級時,便於同名的方法或者變量向下兼容。
系統Symbol
- 除了本身建立Symbol標記以外,ES6還提供了一系列內置的well-know(衆所周知)的Symbol標記,用於改變JavaScript底層API的行爲
API |
desc |
Symbol.hasInstance |
當調用instanceof運算符判斷實例時,會調用這個方法 |
Symbol.isConcatSpreadable |
當調用Array.prototype.concat()時,判斷是否展開 |
Symbol.unscopables |
對象指定使用with關鍵字時,哪些屬性會被with環境排除 |
Symbol.match |
當執行str.match(obj)時,若是該屬性存在會調用它,並返回方法的返回值 |
Symbol.replace |
當執行str.replace(obj)時調用,並返回方法的返回值 |
Symbol.search |
當執行str.search(obj)時調用,並返回方法的返回值 |
Symbol.split |
當執行str.split(obj)時調用,並返回方法的返回值 |
Symbol.iterator |
當對象進行for...of循環時,調用Symbol.iterator方法,返回該對象默認遍歷器 |
Symbol.toPrimitive |
當對象被轉換爲原始數據類型時調用,返回該對象對應的原始數據類型 |
Symbol.toStringTag |
在該對象調用toString方法時調用,返回方法的返回值 |
Symbol.species |
建立衍生對象時使用該屬性 |
參考