1. 概述
- ES6 引入了一種新的原始數(shù)據(jù)類型
Symbol
富蓄,表示獨一無二的值。它是 JavaScript 語言的第七種數(shù)據(jù)類型尚镰, -
Symbol
函數(shù)可以接受一個字符串作為參數(shù),表示對Symbol實例的描述,主要為了在控制臺顯示,或者轉(zhuǎn)為字符串時,比較容易區(qū)分.
let s1 = Symbol('foo')
let s2= Symbol('bar')
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // 'Symbol(foo)'
s2.toString() // 'Symbol(bar)'
- 如果Symbol參數(shù)是一個對象,就會調(diào)用該對象的
toString
方法.將其轉(zhuǎn)化為字符串,然后在生成一個Symbol值 -
Symbol
函數(shù)的參數(shù)只是表示當前Symbol值得描述,因此相同參數(shù)的Symbol
函數(shù)的返回值是不相等的
// 沒有參數(shù)的情況
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有參數(shù)的情況
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
Symbol值不能與其他類型的值進行運算,會報錯
let sym = Symbol('My symbol');
"your symbol is " + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string
- Symbol 值可以顯式轉(zhuǎn)為字符串阀圾。也可以轉(zhuǎn)為布爾值 但是不能轉(zhuǎn)為數(shù)值。
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
2. 作為屬性名的 Symbol
由于每一個 Symbol 值都是不相等的狗唉,這意味著 Symbol 值可以作為標識符初烘,用于對象的屬性名,就能保證不會出現(xiàn)同名的屬性。這對于一個對象由多個模塊構(gòu)成的情況非常有用肾筐,能防止某一個鍵被不小心改寫或覆蓋哆料。
let mySymbol = Symbol();
// 第一種寫法
let a = {};
a[mySymbol] = 'Hello!';
// 第二種寫法
let a = {
[mySymbol]: 'Hello!'
};
// 第三種寫法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上寫法都得到同樣結(jié)果
a[mySymbol] // "Hello!"
// 在對象的內(nèi)部,使用 Symbol 值定義屬性時吗铐,Symbol 值必須放在方括號之中东亦。
// Symbol 值作為屬性名時,該屬性還是公開屬性唬渗,不是私有屬性典阵。
3. 實例:消除魔術(shù)字符串
魔術(shù)字符串指的是,在代碼之中多次出現(xiàn)镊逝、與代碼形成強耦合的某一個具體的字符串或者數(shù)值壮啊。風(fēng)格良好的代碼,應(yīng)該盡量消除魔術(shù)字符串撑蒜,改由含義清晰的變量代替
const shapeType = {
triangle: Symbol()
}; // 用于替換getArea里的 Triangle
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔術(shù)字符串
area = .5 * options.width * options.height;
break;
/* ... more code ... */
}
return area;
}
getArea('Triangle', { width: 100, height: 100 }); // 魔術(shù)字符串
4. 屬性名的遍歷
Symbol 作為屬性名歹啼,該屬性不會出現(xiàn)在for...in
、for...of
循環(huán)中减江,也不會被Object.keys()
染突、Object.getOwnPropertyNames()
、JSON.stringify()
返回辈灼。但是份企,它也不是私有屬性,有一個Object.getOwnPropertySymbols
方法巡莹,可以獲取指定對象的所有Symbol
屬性名司志。
Object.getOwnPropertySymbols
方法返回一個數(shù)組,成員是當前對象的所有用作屬性名的 Symbol
值降宅。
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]
Reflect.ownKeys
方法可以返回所有類型的鍵名骂远,包括常規(guī)鍵名和 Symbol 鍵名。返回數(shù)組
造成了一種非私有的內(nèi)部方法的效果腰根。
let size = Symbol('size');
class Collection {
constructor() {
this[size] = 0;
}
add(item) {
this[this[size]] = item;
this[size]++;
}
static sizeOf(instance) {
return instance[size];
}
}
let x = new Collection();
Collection.sizeOf(x) // 0
x.add('foo');
Collection.sizeOf(x) // 1
Object.keys(x) // ['0']
Object.getOwnPropertyNames(x) // ['0']
Object.getOwnPropertySymbols(x) // [Symbol(size)]
5. Symbol.for()激才,Symbol.keyFor()
我們希望重新使用同一個 Symbol 值,Symbol.for
方法可以做到這一點额嘿。它接受一個字符串作為參數(shù)瘸恼,然后搜索有沒有以該參數(shù)作為名稱的 Symbol 值。如果有册养,就返回這個 Symbol 值东帅,否則就新建并返回一個以該字符串為名稱的 Symbol 值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
-
Symbol.for()
與Symbol()
這兩種寫法球拦,都會生成新的 Symbol靠闭。
比如帐我,如果你調(diào)用Symbol.for("cat")
30 次,每次都會返回同一個 Symbol 值愧膀,但是調(diào)用Symbol("cat")30
次拦键,會返回 30 個不同的 Symbol 值。
Symbol.keyFor
方法返回一個已登記的 Symbol 類型值的key
扇调。
7. 內(nèi)置的 Symbol 值
-
Symbol.hasInstance
對象的Symbol.hasInstance
屬性矿咕,指向一個內(nèi)部方法抢肛。當其他對象使用instanceof
運算符狼钮,判斷是否為該對象的實例時,會調(diào)用這個方法捡絮。比如熬芜,foo instanceof Foo
在語言內(nèi)部,實際調(diào)用的是Foo[Symbol.hasInstance](foo)
福稳。 -
item.recentVacancyCount
對象的Symbol.isConcatSpreadable
屬性等于一個布爾值涎拉,表示該對象用于Array.prototype.concat()
時,是否可以展開 -
Symbol.species
對象的Symbol.species
屬性的圆,指向一個構(gòu)造函數(shù)鼓拧。創(chuàng)建衍生對象時,會使用該屬性越妈。 -
Symbol.match
對象的Symbol.match
屬性季俩,指向一個函數(shù)。當執(zhí)行str.match(myObject)
時梅掠,如果該屬性存在酌住,會調(diào)用它,返回該方法的返回值阎抒。 -
Symbol.replace
對象的Symbol.replace
屬性酪我,指向一個方法,當該對象被String.prototype.replace
方法調(diào)用時且叁,會返回該方法的返回值都哭。 -
Symbol.search
對象的Symbol.search
屬性,指向一個方法逞带,當該對象被String.prototype.search
方法調(diào)用時欺矫,會返回該方法的返回值。 -
Symbol.split
對象的Symbol.split
屬性掰担,指向一個方法汇陆,當該對象被String.prototype.split
方法調(diào)用時,會返回該方法的返回值带饱。 -
Symbol.iterator
對象的Symbol.iterator
屬性毡代,指向該對象的默認遍歷器方法阅羹。 -
Symbol.toPrimitive
對象的Symbol.toPrimitive
屬性,指向一個方法教寂。該對象被轉(zhuǎn)為原始類型的值時捏鱼,會調(diào)用這個方法,返回該對象對應(yīng)的原始類型值酪耕。 -
Symbol.toStringTag
對象的Symbol.toStringTag
屬性导梆,指向一個方法。在該對象上面調(diào)用Object.prototype.toString
方法時迂烁,如果這個屬性存在看尼,它的返回值會出現(xiàn)在toString
方法返回的字符串之中,表示對象的類型盟步。也就是說藏斩,這個屬性可以用來定制[object Object]
或[object Array]
中object后面的那個字符串。
ES6 新增內(nèi)置對象的Symbol.toStringTag
屬性值如下却盘。
JSON[Symbol.toStringTag]
:'JSON'
Math[Symbol.toStringTag]
:'Math'
Module 對象M[Symbol.toStringTag]
:'Module'
ArrayBuffer.prototype[Symbol.toStringTag]
:'ArrayBuffer'
DataView.prototype[Symbol.toStringTag]
:'DataView'
Map.prototype[Symbol.toStringTag]
:'Map'
Promise.prototype[Symbol.toStringTag]
:'Promise'
Set.prototype[Symbol.toStringTag]
:'Set'
%TypedArray%.prototype[Symbol.toStringTag]
:'Uint8Array'等
WeakMap.prototype[Symbol.toStringTag]
:'WeakMap'
WeakSet.prototype[Symbol.toStringTag]
:'WeakSet'
%MapIteratorPrototype%[Symbol.toStringTag]
:'Map Iterator'
%SetIteratorPrototype%[Symbol.toStringTag]
:'Set Iterator'
%StringIteratorPrototype%[Symbol.toStringTag]
:'String Iterator'
Symbol.prototype[Symbol.toStringTag]
:'Symbol'
Generator.prototype[Symbol.toStringTag]
:'Generator'
GeneratorFunction.prototype[Symbol.toStringTag]
:'GeneratorFunction' -
Symbol.unscopables
對象的Symbol.unscopables
屬性狰域,指向一個對象。該對象指定了使用with關(guān)鍵字時黄橘,哪些屬性會被with環(huán)境排除兆览。