symbol
ES6 增加了一個新的基本數(shù)據(jù)類型 symbol. 不過,和其他基本數(shù)據(jù)類型相比,它有點與眾不同,因為它沒有字面量的表現(xiàn)形式噪漾,而且創(chuàng)建的方式也有點奇怪,只能通過調用全局函數(shù)Symbol()來完成且蓬。
let firstSymbol = Symbol();
這里注意一點欣硼,Symbol函數(shù)調用的時候,前面不要加new. 創(chuàng)建了一個symbol, 它有什么作用呢恶阴? 可以把它看作一個類字符串诈胜,和字符串的使用方式一致,字符串能用的地方冯事,symbol 基本都能用焦匈,最常用的地方就是作為對象的屬性名使用,因為桅咆,symbol創(chuàng)建的起因是一項對象的私有屬性的提議括授,落實到規(guī)范中,私有屬性去除掉了岩饼,對象的屬性保留下來了
let firstSymbol = Symbol();
let person = {
[firstSymbol]: 'symbolName'
}
let dog = {};
dog[firstSymbol] = "sybolName"
symbol 是唯一的荚虚,它和任何其他symbol 都不相等,避免了屬性名的沖突籍茧。
let firstSymbol = Symbol();
let secondSymbol = Symbol();
console.log(firstSymbol == secondSymbol) // false
這么調用Symbol() 函數(shù)也有問題版述,就是程序出問題, 進行debugger 的時候寞冯,不是很容易找到哪個symbol 出現(xiàn)的問題渴析,所以Symbol 函數(shù)可以接受一個字符串, 對這個symbol 進行描述吮龄。
let firstSymbol = Symbol('first symbol');
let secondSymbol = Symbol('second symbol');
console.log(secondSymbol) //Symbol(second symbol)
symbol的描述存在于每一個symbol 的內(nèi)部屬性 [[Description]] 中俭茧,外部是無法獲取的,不過漓帚,可以通過顯示或隱式調用toString() 方法來獲取母债, console.log 就是通過隱式調用toString 方法來獲取描述的。
但是有時候,你不想要這種唯一性毡们, 可能所有的對象都共用一個symbol 屬性迅皇, 這怎么辦? 在一個文件js中衙熔,很好處理登颓,所有的對象都使用這一個symbol 變量就可以了,但跨文件就不好處理了红氯,尤其是提倡模塊化的今天框咙,每一個文件都是一個模塊,都有自己的私有作用域脖隶。在這種情況下扁耐,就要使用共享symbol 了,創(chuàng)建symbol 變量的時候产阱,使用Symbol.for() 方法婉称,參數(shù)是一個字符串, 可以理解為共享標識key,
let uid = Symbol.for('uid');
當我們使用Symbol.for() 創(chuàng)建symbol 的時候构蹬,js 引擎就會向全局symbol 注冊中心去查找這個symbol, 查找的依據(jù)是唯一的標識key(在這里是‘’uid‘’)王暗, 如果找到了,就直接返回庄敛,如果沒有找到俗壹,就創(chuàng)建一個新的symbol,并使用唯一的標識key注冊到全局注冊中心藻烤,然后返回它绷雏, 這樣,我們以后再使用這個key 創(chuàng)建 symbol, 就會獲取到同一個symbol, 這就共享了怖亭。舉個例子驗證一下
let uid1 = Symbol.for('uid');
let uid2 = Symbol.for('uid');
console.log(uid1 === uid2); // true
還有一個Symbol.keyFor() 方法涎显,可以獲取到一個symbol 在全局注冊中心中注冊的唯一標識key。
let uid1 = Symbol.for('uid');
let symbolKey = Symbol.keyFor(uid1);
console.log(symbolKey) // 'uid'
如果一個對象中有多個symbol 屬性兴猩,是不是可以一次性地獲取到期吓? 你可能想到了Object.keys() 方法,但是它對symbol 不起作用倾芝,為了獲取到symbol 屬性讨勤,js 專門定義了一個方法,Object.getOwnPropertySymbols(), 它返回一個包含所有symbol 屬性地數(shù)組晨另。
let uid = Symbol.for("uid");
let object = {
[uid]: "12345"
};
let symbols = Object.getOwnPropertySymbols(object);
console.log(symbols.length); // 1
console.log(symbols[0]); // "Symbol(uid)"
console.log(object[symbols[0]]); // "12345"
當然潭千,如果僅僅是為了給對象簡單地添加屬性,就增加一個symbol 類型和Symbol() 函數(shù)借尿,那就有點大才小用了刨晴。添加Symbol 還要一個很大的作用,就是暴露js的一些內(nèi)部方法(Exposing Internal Operations), 為此, js 定義了一些有名的symbol (well-known symbols)割捅, 這些symbols 都是增加到Symbol 對象上。
Symbol.hasInstance
每一個函數(shù)都有一個Symbol.hasInstance方法帚桩,主要是判斷一個對象是不是一個函數(shù)的實例亿驾,就是平常我們使用的instanceOf 方法. obj instanceOf Array, 實際上就是調用Array 函數(shù)上面的Symbol.hasInstance 方法账嚎,Array [ Symbol.hasInstance] (obj), 可以發(fā)現(xiàn)莫瞬,Symbol.hasInstance 方法 接受一個參數(shù)就是我們要檢查的對象,然后返回true or false, 來表示檢查的對象是不是函數(shù)的實例郭蕉, true 就表示是疼邀,false 表示不是。寫一個簡單的例子體驗一下
首先必須有一個函數(shù)召锈, 那就聲明一個函數(shù)Person
function Person(name) {
this.name = name;
}
現(xiàn)在使用instanceOf 方法驗證一下
console.log(new Person('sam') instanceof Person);
你會發(fā)現(xiàn)旁振,返回true, 但是 我們明明返回的是false, 是哪個地方出問題了? 這是因為每一個函數(shù)都有一個默認的Symbol.hasInstance, 它位于函數(shù)的原型鏈Function.prototype 上涨岁, 我們在Person 函數(shù)上定義Symbol.hasInstance方法是相當于遮蔽原型鏈上的方法拐袜,但是在原型鏈上定義的Symbol.hasInstance 方法,它是不可配置梢薪,不可改寫蹬铺,不可迭代的。正是由于不可改寫秉撇,像Person[Symbol.hasInstance] 普通賦值的方式無法真正實現(xiàn)賦值甜攀,靜默失敗。那怎么才能遮蔽原型鏈上Symbol.hasInstance 方法琐馆, 使用Object.defineProperty 方式進行賦值
Object.defineProperty(Person, Symbol.hasInstance, {
value: function(value) {
return false;
}
})
這時候 console.log 就返回false了规阀。