ECMAScript 6-Symbol
Symbol
背景:ES5的物件屬性名都是字串,這容易造成屬性名的衝突。ES6引入了一種新的原始資料型別Symbol,表示獨一無二的值,它就是Symbol資料型別
特性
1. Symbol值通過Symbol函式生成,它是一種類似於字串的資料型別
-----
let s = Symbol();
2. Symbol函式可以接受一個字串作為引數,表示對Symbol例項的描述。即使引數相同,Symbol函式的返回值依舊是不相等的 ----- var s = Symbol('foo'); s//Symbol(foo) var s1 = Symbol('foo'); var s2 = Symbol('foo'); s1 === s2 // false
3. Symbol值不能與其他型別的值進行運算
-----
var sym = Symbol('My symbol');
"your symbol is " + sym //error
`your symbol is ${sym}` //error
4. Symbol值可以轉為字串、布林值,但不能轉為數值
-----
var s = Symbol();
s.toString() // "Symbol()"
Boolean(s) // true
Number(s) // TypeError
如何作為屬性名
由於每一個Symbol值都是不相等的,這意味著Symbol值可以作為識別符號,用於物件的屬性名,就能保證不會出現同名的屬性
-
將Symbol作為屬性名的三種寫法
var mySymbol = Symbol(); // 第一種寫法 var a = {}; a[mySymbol] = 'Hello!'; // 第二種寫法 var a = { [mySymbol]: 'Hello!' }; // 第三種寫法 var a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上寫法都得到同樣結果 a[mySymbol] // "Hello!"
-
Symbol值作為物件屬性名時,不能用點運算子
var mySymbol = Symbol(); var a = {}; a.mySymbol = 'Hello!'; //不可以這樣寫
//解析:因為點運算子後面總是字串,所以不會讀取mySymbol作為標識名所指代的那個值,導致a的屬性名實際上是一個字串,而不是一個Symbol值。 //結果: a[mySymbol] // undefined a['mySymbol'] // "Hello!"
屬性名的遍歷
-
Object.getOwnPropertySymbols()
:返回一個數組,成員是當前物件的所有用作屬性名的 Symbol 值var obj = {}; var a = Symbol('a'); //建立symbol var b = Symbol('b'); //建立symbol obj[a] = 'Hello'; //symbol作為屬性名 obj[b] = 'World'; //symbol作為屬性名 var objectSymbols = Object.getOwnPropertySymbols(obj); //遍歷屬性名 objectSymbols // [Symbol(a), Symbol(b)]
-
Reflect.ownKeys()
:可以返回所有型別的鍵名,包括常規鍵名和 Symbol 鍵名let obj = { [Symbol('my_key')]: 1, enum: 2, nonEnum: 3 }; Reflect.ownKeys(obj) // ["enum", "nonEnum", Symbol(my_key)]
一些方法
-
Symbol.for()
:接受一個字串作為引數,搜尋有沒有以該引數作為名稱的Symbol值。如果有,就返回這個Symbol值,否則就新建並返回一個以該字串為名稱的Symbol值var s1 = Symbol.for('foo'); var s2 = Symbol.for('foo'); s1 === s2 // true
-
Symbol.keyFor()
:返回一個用Symbol.for
建立的 Symbol值的keyvar s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" var s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined
內建的Symbol值
-
Symbol.hasInstance
:當其他物件使用instanceof
運算子,判斷是否為該物件的例項時,會呼叫這個方法。比如,foo instanceof Foo
在語言內部,實際呼叫的是Foo[Symbol.hasInstance](foo)
-
Symbol.hasInstance
:等於一個布林值,表示該物件使用Array.prototype.concat()
時,是否可以展開 。預設等於undefined,表示可以展開,true也表示可展開;當如果為false,表示需要手動展開let arr1 = ['c', 'd']; arr1[Symbol.isConcatSpreadable] // undefined //預設是undefined,可展開 ['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
let arr1 = ['c', 'd']; arr1[Symbol.isConcatSpreadable] = false; ['a', 'b'].concat(arr1, 'e') // ['a', 'b', ['c','d'], 'e']
-
Symbol.species
:指向當前物件的建構函式。創造例項時,預設會呼叫這個方法,即使用這個屬性返回的函式當作建構函式,來創造新的例項物件 -
Symbol.match
:指向一個函式。當執行str.match(myObject)
時,如果該屬性存在,會呼叫它,返回該方法的返回值 -
Symbol.replace
:指向一個方法,當該物件被String.prototype.replace
方法呼叫時,會返回該方法的返回值 -
Symbol.search
:指向一個方法,當該物件被String.prototype.search
方法呼叫時,會返回該方法的返回值 -
Symbol.split
:指向一個方法,當該物件被String.prototype.split
方法呼叫時,會返回該方法的返回值 -
Symbol.iterator
:指向該物件的預設遍歷器方法 -
Symbol.toPrimitive
:指向一個方法。該物件被轉為原始型別的值時,會呼叫這個方法,返回該物件對應的原始型別值 -
Symbol.toStringTag
:指向一個方法。在該物件上面呼叫Object.prototype.toString方法時,如果這個屬性存在,它的返回值會出現在toString方法返回的字串之中,表示物件的型別。也就是說,這個屬性可以用來定製[object Object]
或[object Array]
中object
後面的那個字串ES6新增內建物件的
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
:指向一個物件。該物件指定了使用with關鍵字時,哪些屬性會被with環境排除。