Symbol
- 概述
- 作為屬性名的symbol
- 屬性名的遍歷
- Symbol的方法
- 內(nèi)置的symbol值
概述
Symbol的原理:保證每一個屬性名都是獨(dú)一無二的潜的,從根本上防止屬性名的沖突。
symbol
表示獨(dú)一無二的值字管,是JavaScript的第七種數(shù)據(jù)類型啰挪。
生成
Symbol
值通過Symbol函數(shù),對象的屬性名現(xiàn)在可以有兩種類型嘲叔,一種是原來就有的字符串亡呵,另一種就是新增的 Symbol 類型。而Symbol類型的屬性名都是獨(dú)一無二的硫戈,保證不會與其他屬性名發(fā)生沖突锰什。
let s = Symbol();
typeof s;//Symbol
<mark>注意</mark>:Symbol函數(shù)前不能用new
命令,這是因?yàn)樯傻?Symbol 是一個原始類型的值,不是對象歇由。
Symbol函數(shù)接受參數(shù)
字符串為參數(shù)(Symbol實(shí)例的描述卵牍,在打印時易于區(qū)分)
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
對象為參數(shù)
先調(diào)用對象的toString()
方法將其轉(zhuǎn)為字符串,然后再生成Symbol值沦泌。
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
<mark>注意</mark>:
1.Symbol
函數(shù)的參數(shù)只是表示對當(dāng)前 Symbol 值的描述糊昙,因此相同參數(shù)的Symbol
函數(shù)的返回值是不相等的。
2.Symbol值不能與其他類型的值進(jìn)行運(yùn)算
3.Symbol值可以顯式轉(zhuǎn)為字符串
4.Symbol值可以轉(zhuǎn)為布爾型谢谦,但不能轉(zhuǎn)為數(shù)值释牺。
作為屬性名的Symbol值
由于每一個 Symbol 值都是不相等的,這意味著 Symbol 值可以作為標(biāo)識符回挽,用于對象的屬性名没咙,就能保證不會出現(xiàn)同名的屬性。這對于一個對象由多個模塊構(gòu)成的情況非常有用千劈,能防止某一個鍵被不小心改寫或覆蓋祭刚。
let mySymbol = Symbol();
let a={};
a[Symbol]='Hello'//寫法一
Object.defineProperty(a,mySymbol,{ value: 'Hello' });//寫法二
<mark>注意</mark>:
1.Symbol作為對象屬性名時,不能用點(diǎn)運(yùn)算符墙牌。(點(diǎn)運(yùn)算符后面總是字符串)
2.在對象的內(nèi)部涡驮,使用 Symbol 值定義屬性時,Symbol 值必須放在方括號之中喜滨。方括號中的屬性名代表了Symbol值捉捅。
3.Symbol 值作為屬性名時,該屬性還是公開屬性虽风,不是私有屬性棒口。
魔術(shù)字符串
在代碼之中多次出現(xiàn)、與代碼形成強(qiáng)耦合的某一個具體的字符串或者數(shù)值辜膝。
屬性名的遍歷
Symbol 作為屬性名无牵,該屬性不會出現(xiàn)在for...in
、for...of
循環(huán)中厂抖,也不會被Object.keys()
合敦、Object.getOwnPropertyNames()
、JSON.stringify()
返回验游。但是,它也不是私有屬性保檐,有一個Object.getOwnPropertySymbols
方法耕蝉,可以獲取指定對象的所有 Symbol 屬性名。
-
Object.getOwnPropertySymbols()
:返回一個數(shù)組夜只,成員是當(dāng)前對象的所有用作屬性名的 Symbol 值垒在。 -
Reflect.ownKeys()
:返回所有類型的鍵名。
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
Symbol的方法
Symbol.for()
(重新使用同一個Symbol值)
它接受一個字符串作為參數(shù)扔亥,然后搜索有沒有以該參數(shù)作為名稱的 Symbol 值场躯。如果有谈为,就返回這個 Symbol 值,否則就新建并返回一個以該字符串為名稱的 Symbol 值踢关。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
Symbol.for()
不會每次調(diào)用就返回一個新的Symbol類型的值伞鲫,而是會先檢查給定的key值是否已經(jīng)存在,不存在的話才會新建一個值签舞。而Symbol.()
方法沒有登記機(jī)制秕脓,所以每次調(diào)用都是不同的值。
Symbol.Keyfor()
返回一個已登記的Symbol類型的值Key儒搭。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
Singleton 模式
Singleton模式指的是調(diào)用一個類吠架,任何時候返回的都是同一個實(shí)例。
內(nèi)置的Symbol對象
Symbol.hasInstance
對象的該屬性指向一個內(nèi)部方法搂鲫。當(dāng)其他對象使用instanceof運(yùn)算符傍药,判斷是否為該對象的實(shí)例時,會調(diào)用這個方法魂仍。比如拐辽,foo instanceof Foo在語言內(nèi)部,實(shí)際調(diào)用的是Foo[Symbol.hasInstance] (foo)
蓄诽。
Symbol.isConcatSpreadable(默認(rèn)等于undefined)
對象的Symbol.isConcatSpreadable
屬性等于一個布爾值薛训,表示該對象用于Array.prototype.concat()
時,是否可以展開仑氛。
//數(shù)組的默認(rèn)行為可以展開
let arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined
let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
//數(shù)組的對象默認(rèn)不展開
let obj = {length: 2, 0: 'c', 1: 'd'};
['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']
obj[Symbol.isConcatSpreadable] = true;
['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']
Symbol.species
對象的Symbol.species屬性乙埃,指向一個構(gòu)造函數(shù)。創(chuàng)建衍生對象時锯岖,會使用該屬性介袜。
class MyArray extends Array {
static get [Symbol.species]() { return Array; }
}
const a = new MyArray();
const b = a.map(x => x);
b instanceof MyArray // false
b instanceof Array // true
Symbol.match
對象的Symbol.match屬性,指向一個函數(shù)出吹。當(dāng)執(zhí)行str.match(myObject)時遇伞,如果該屬性存在,會調(diào)用它捶牢,返回該方法的返回值鸠珠。
String.prototype.match(regexp)
// 等同于
regexp[Symbol.match](this)
class MyMatcher {
[Symbol.match](string) {
return 'hello world'.indexOf(string);
}
}
'e'.match(new MyMatcher()) // 1
Symbol.replace
對象的Symbol.replace屬性,指向一個方法秋麸,當(dāng)該對象被String.prototype.replace
方法調(diào)用時渐排,會返回該方法的返回值。
-
symbol.replace
接受兩個參數(shù):第一個參數(shù)是replace方法正在作用的對象灸蟆,第二個參數(shù)是替換后的值驯耻。String.prototype.replace(searchValue, replaceValue) // 等同于 searchValue[Symbol.replace](this, replaceValue)
Symbol.search
對象的Symbol.search
屬性,指向一個方法,當(dāng)該對象被String.prototype.search
方法調(diào)用時可缚,會返回該方法的返回值霎迫。
String.prototype.search(regexp)
// 等同于
regexp[Symbol.search](this)
class MySearch {
constructor(value) {
this.value = value;
}
[Symbol.search](string) {
return string.indexOf(this.value);
}
}
'foobar'.search(new MySearch('foo')) // 0
Symbol.split
對象的Symbol.split
屬性,指向一個方法帘靡,當(dāng)該對象被String.prototype.split
方法調(diào)用時知给,會返回該方法的返回值。
String.prototype.split(separator, limit)
// 等同于
separator[Symbol.split](this, limit)
class MySplitter {
constructor(value) {
this.value = value;
}
[Symbol.split](string) {
let index = string.indexOf(this.value);
if (index === -1) {
return string;
}
return [
string.substr(0, index),
string.substr(index + this.value.length)
];
}
}
'foobar'.split(new MySplitter('foo'))
// ['', 'bar']
'foobar'.split(new MySplitter('bar'))
// ['foo', '']
'foobar'.split(new MySplitter('baz'))
// 'foobar'
Symbol.iterator
對象的Symbol.iterator
屬性测柠,指向該對象的默認(rèn)遍歷器方法炼鞠。
對象進(jìn)行for...of
循環(huán)時,會調(diào)用Symbol.iterator方法轰胁,返回該對象的默認(rèn)遍歷器谒主。
class Collection {
*[Symbol.iterator]() {
let i = 0;
while(this[i] !== undefined) {
yield this[i];
++i;
}
}
}
let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;
for(let value of myCollection) {
console.log(value);
}
// 1
// 2
Symbol.toPrimitive
對象的Symbol.toPrimitive
屬性,指向一個方法赃阀。該對象被轉(zhuǎn)為原始類型的值時霎肯,會調(diào)用這個方法,返回該對象對應(yīng)的原始類型值榛斯。
Symbol.toPrimitive
:一個字符串參數(shù)观游,表示當(dāng)前運(yùn)算的模式,一共有三種模式驮俗。
Number:該場合需要轉(zhuǎn)成數(shù)值
String:該場合需要轉(zhuǎn)成字符串
-
Default:該場合可以轉(zhuǎn)成數(shù)值懂缕,也可以轉(zhuǎn)成字符串
let obj = { [Symbol.toPrimitive](hint) { switch (hint) { case 'number': return 123; case 'string': return 'str'; case 'default': return 'default'; default: throw new Error(); } } }; 2 * obj // 246 3 + obj // '3default' obj == 'default' // true String(obj) // 'str'
Symbol.toStringTag
對象的Symbol.toStringTag
屬性,指向一個方法王凑。在該對象上面調(diào)用Object.prototype.toString
方法時搪柑,如果這個屬性存在,它的返回值會出現(xiàn)在toString方法返回的字符串之中索烹,表示對象的類型工碾。
// 例一
({[Symbol.toStringTag]: 'Foo'}.toString())
// "[object Foo]"
// 例二
class Collection {
get [Symbol.toStringTag]() {
return 'xxx';
}
}
let x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"
Symbol.unscopables
對象的Symbol.unscopables
屬性,指向一個對象百姓。<mark>該對象指定了使用with關(guān)鍵字時渊额,哪些屬性會被with環(huán)境排除。</mark>
Array.prototype[Symbol.unscopables]
// {
// copyWithin: true,
// entries: true,
// fill: true,
// find: true,
// findIndex: true,
// includes: true,
// keys: true
// }
Object.keys(Array.prototype[Symbol.unscopables])
// ['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'includes', 'keys']
<mark>上面代碼說明垒拢,數(shù)組有 7 個屬性旬迹,會被with命令排除。</mark>