1:Symbol
引入的原因:
防止在混入新屬性時馋贤,屬性名沖突
這樣對象的屬性名現(xiàn)在可以有兩種類型:一種就是字符串责球,一種就是新增的Symbol類型。凡是Symbol類型的屬性名贸典,都是獨一無二的视卢,可以保證不會和其他屬性名產(chǎn)生沖突。
含義:symbol表示獨一無二的值廊驼,是js語言的第七種數(shù)據(jù)類型
使用語法:通過Symbol函數(shù)生成 据过,Symbol函數(shù)前不能使用new命令。否則會報錯
let s = Symbol();
Symbol函數(shù)可以接受一個字符串作為參數(shù)妒挎,表示對Symbol實例的描述绳锅,主要是為了在控制臺顯示,或者轉(zhuǎn)為字符串時酝掩,比較容易區(qū)分鳞芙。
總結(jié)一句話:加描述,就是為了區(qū)分不同的symbol類型的屬性庸队,相同參數(shù)的Symbol函數(shù)的返回值是不相等的
let s = Symbol('dgsg')
let s2 = Symbol('dgsg')
s === s2 // false 相同參數(shù)的Symbol函數(shù)的返回值是不相等的
如果Symbol的參數(shù)是一個對象积蜻,就會調(diào)用該對象的toString方法,將其轉(zhuǎn)為字符串彻消,然后才生成一個Symbol值
let s = Symbol({toString(){return 'ere'}})
s // Symbol(ere)
Symbol值不能像字符串一樣參與運算竿拆,會報錯,
但是可以顯示轉(zhuǎn)為字符串
let sym = Symbol('My symbol')
String(sym) // "Symbol(My symbol)" 即便是可以顯示轉(zhuǎn)為字符串但也不能和字符串進行拼接運算
"your symbol is " + sym // TypeError: can't convert symbol to string
Symbol值可以轉(zhuǎn)為布爾值宾尚,但是不能轉(zhuǎn)為數(shù)值
2: Symbol.prototype.description
方便讀取symbol值的描述:
let sym = Symbol('My symbol')
sym.description // "My symbol"
3:作為屬性名的Symbol
由于每一個Symbol值都不相等丙笋,意味著用于對象屬性名,就能保證不會出現(xiàn)同名的屬性煌贴。對于一個對象由多個模塊構(gòu)成的情況非常有用御板。能防止某一個鍵被不小心改寫或覆蓋。
作為對象的屬性名時使用[](方括號)語法牛郑,不能使用.(點)語法怠肋,因為點運算符后面總是字符串,所以不會讀取symbol作為標(biāo)識符所指代的那個值淹朋。
Symbol類型還可以用于定義一組常量笙各,保證這組常量的值都是不相等的钉答。
const log={}
log.levels = {
DEBUG:Symbol('debug'),
INFO:Symbol('info'),
WARN:Symbol('warn')
}
常量使用Symbol的最大的好處,就是其他任何值都不可能有相同值杈抢,
Symbol值作為屬性名時数尿,該屬性還是公開屬性,不是私有屬性惶楼。
4:消除魔術(shù)字符串
魔術(shù)字符串右蹦,就是指在代碼中多次出現(xiàn),與代碼形成強耦合的某一個具體字符串或者數(shù)值歼捐,風(fēng)格良好的代碼何陆,應(yīng)該盡量消除魔術(shù)字符串,改由含義清晰的變量替代窥岩。
常用的方法是:將它寫成一個變量甲献。
由于該變量等于那個值其實并不重要宰缤,重要的是不會跟其他的屬性值沖突即可颂翼。因為消除魔術(shù)字符串就很適合使用Symbol值。
5:屬性名的遍歷:
for...in
for...of
Object.keys
Object.getOwnPropertyNames
JSON.stringify
以上都不會返回Symbol屬性名的屬性
Object.getOwnPropertySymbols會返回所有的Symbol屬性
let s={
[Symbol('d')]:'erer', //symbol值作為屬性名
[Symbol('s')](){//}, //symbol值作為函數(shù)名
c:'12'
}
Object.getOwnPropertySymbols(s) // [Symbol(d)]
另一個新的API:Reflect.ownKeys() 可以返回所有類型的鍵名慨灭,包括常規(guī)鍵名和Symbol鍵名朦乏。
Reflect.ownKeys(s) // ['c',Symbol(d)]
由于Symbol值作為鍵名,不會被常規(guī)方法遍歷得到氧骤,可以利用這個特性呻疹,為對象定義一些非私有的,但又希望只用于內(nèi)部的方法筹陵。
6:Symbol.for Symbol.keyFor
使用同一個值刽锤,Symbol.for接受一個字符串參數(shù),搜索有沒有以該參數(shù)作為名稱的Symbol值朦佩,如果有并思,就返回這個Symbol值,否則就新建一個以該字符串為名稱的Symbol值语稠,并將其注冊到全局宋彼。Symbol.for和Symbol.keyFor都是對注冊的symbol,Symbol.for會將生成的變量進行注冊仙畦,Symbol不進行注冊输涕。
let s1 = Symbol.for('sdfsf')
let s3 = Symbol.for('sdfsf')
s1 === s3 // true 表示Symbol.for('sdfsf') 直接返回了已定義的s1 并賦值給s3
Symbol.for 和Symbol都會生成Symbol值,區(qū)別是慨畸,
1:Symbol.for會被登記到全局環(huán)境中供搜索莱坎,Symbol不會。
2:Symbol.for不會每次調(diào)用返回一個新的Symbol類型的值寸士,而是先檢查給定的key是否已經(jīng)存在檐什,如果不存在才會新建一個值瞳收。而 Symbol()寫法沒有登記機制,所以每次調(diào)用都會返回一個不同的值厢汹。
Symbol.keyFor 返回一個已登記的Symbol類型值的key
Symbol.keyFor(s3) // "sdfsf"
Symbol.keyFor(s4) // undefined
Symbol.for即便是在函數(shù)內(nèi)容生成的螟深,但是也是登記到全局中,這個全局登記特性烫葬,可以用在不同的iframe或service worker中取到同一個值界弧。
7:模塊的Singleton模式
Singleton模式指的是調(diào)用一個類,任何時候返回的都是同一個實例搭综。
// mod.js
const FOO_KEY = Symbol.for('foo');
function A() {
this.foo = 'hello';
}
if (!global[FOO_KEY]) {
global[FOO_KEY] = new A();
}
module.exports = global[FOO_KEY];
8:內(nèi)置的Symbol值
11個內(nèi)置的Symbol值垢箕。
Symbol.hasInstance:指向一個內(nèi)部方法。當(dāng)其他對象使用instanceof運算符兑巾,判斷是否為該對象的實例時条获,會調(diào)用該方法。
Symbol.isConcatSpreadable:指向一個布爾值蒋歌,表示該對象用于Array.prototype.concat時帅掘,是否可以展開。
let arr = [1,23,4]
arr[Symbol.isConcatSpreadable] // undefined 數(shù)組默認是展開的
[5,6,7].concat(arr,0,5) // [5, 6, 7, 1, 23, 4, 0, 5] 默認是展開的堂油,所以concat后就直接是展開的數(shù)組
let obj = {c:1,d:5}
['a','d'].concat(obj,'e') // ["a", "d", {…}, "e"] 對象是默認不展開的
Symbol.species:指向一個構(gòu)造函數(shù)修档,創(chuàng)建衍生對象時,會使用該屬性府框。
Symbol.species的作用在于吱窝,實例對象在運行過程中,需要再次調(diào)用自身的構(gòu)造函數(shù)時迫靖,會調(diào)用該屬性指定的構(gòu)造函數(shù)院峡。
它主要的用途是,有些類庫是在基類的基礎(chǔ)上修改的系宜,那么子類使用繼承的方法時照激,作者可能希望返回基類的實例,而不是子類的實例蜈首。修改父類的指向
Symbol.match:指向一個函數(shù)实抡,執(zhí)行str.match時,如果該屬性存在欢策,會調(diào)用它吆寨,返回該方法的返回值。
Symbol.replace:指向一個方法踩寇,當(dāng)該對象被String.prototype.replace方法調(diào)用時啄清,會返回該方法的返回值。
Symbol.replace方法會收到兩個參數(shù),第一個參數(shù)是replace方法正在作用的對象辣卒,上面例子是Hello掷贾,第二個參數(shù)是替換后的值,上面例子是World荣茫。
Symbol.search:指向一個方法想帅,當(dāng)該對象被String.prototype.search方法調(diào)用時,返回該方法的返回值啡莉。
Symbol.split:指向一個方法港准,當(dāng)該對象被String.prototype.split方法調(diào)用時,返回該方法的返回值咧欣。
Symbol.iterator:指向該對象的默認遍歷器方法浅缸。對象進行for...of循環(huán)時,會調(diào)用Symbol.iterator方法魄咕,返回該對象的默認遍歷器衩椒。
Symbol.toPrimitive:指向一個方法,該對象被轉(zhuǎn)為原始類型的值時哮兰,會調(diào)用這個方法毛萌,返回該對象對應(yīng)的原始類型值。
Symbol.toPrimitive被調(diào)用時奠蹬,會接受一個字符串參數(shù)朝聋,表示當(dāng)前運算的模式,一共有三種模式囤躁。
* Number:該場合需要轉(zhuǎn)成數(shù)值
* String:該場合需要轉(zhuǎn)成字符串
* Default:該場合可以轉(zhuǎn)成數(shù)值,也可以轉(zhuǎn)成字符串
Symbol.toStringTag:指向一個方法荔睹,在該對象調(diào)用Object.prototype.toString方法時狸演,如果這個屬性存在,它的返回值會出現(xiàn)在toString方法返回的字符串之中僻他,表示對象的類型宵距。也就是說,這個屬性可以用來定制[object Object]或[object Array]中的object后面的那個字符串吨拗。
({[Symbol.toStringTag]:'Foo'}.toString()) //'[object Foo]'
Symbol.unscopables:指向一個對象满哪,該對象指定使用with關(guān)鍵字時,哪些屬性會被with環(huán)境排除劝篷。設(shè)定Symbol.unscopables的屬性會被with排除哨鸭。