概述
ES5的對象屬性名都是字符串,這容易造成屬性名的沖突。比如,你使用了一個他人提供的對象,但又想為這個對象添加新的方法(mixin模式),新方法的名字就有可能與現有方法產生沖突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的沖突。這就是ES6引入Symbol的原因。
ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值。它是JavaScript語言的第七種數據類型,前六種是:Undefined、Null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。
Symbol值通過Symbol
函數生成。這就是說,對象的屬性名現在可以有兩種類型,一種是原來就有的字符串,另一種就是新增的Symbol類型。凡是屬性名屬於Symbol類型,就都是獨一無二的,可以保證不會與其他屬性名產生沖突。
Symbol的特性就是唯一性
Symbol(符號)是一種新的基本類型值
基本使用
Symbol的使用就是直接圓括號調用,不能通過new來構造
基本使用
Symbol內部可以傳入參數,參數的作用是對這個符合的描述
let a = Symbol('hello') console.log(a);
Symbol的唯一性
Symbol是代表唯一的意思,同值的Symbol是不相等的
let a = Symbol() let b = Symbol() console.log(a == b);
即使內部傳入參數相同也不相等
let a = Symbol('hello') let b = Symbol('hello') console.log(a == b);
Symbol的內部參數
(1)Symbol內部如果是字符串,表示當前這個符合的描述信息
let a = Symbol('hello') console.log(a)
(2)Symbol內部如果是對象,並且有toString方法,返回的就是這個符合的描述
let a = Symbol({ a: 100, toString: function() { return "symbol的描述信息" } }) console.log(a);
(3)Symbol內部如果是數組,內部的參數會被扁平化,用逗號隔開
let a = Symbol([ 1, 2, 'a', 'b' ]) console.log(a);
Symbol的應用場景
Symbol可以來創建對象的內部屬性,內部屬性的特點是防止外部獲取或者隨意篡改
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 1 } obj.c = 2; console.log(obj);
symbol定義的屬性,外部是無法獲取的,因為我們知道symbol同值是不相等的。所以下面的途徑是獲取不到的
obj[Symbol("objKey")]
上面的結果會返回undefined,因為symbol("objKey") != symbol("objKey")
並且對象遍歷symbol的時候是得不到這個key的
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 300 } for (let item in obj) { console.log(item); }
使用Object.keys方法也不能獲取symbol對應的key
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 300 } console.log(Object.keys(obj));
獲取對象中Symbol的key的方法
第一個方法是Object.getOwnPropertySymbols,返回的是只有symbol定義的key
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 10 } let result = Object.getOwnPropertySymbols(obj) console.log(result)
第二個方法是Reflect.ownKeys,返回的是所有的key,包含symbol定義的key
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 10 } let result = Reflect.ownKeys(obj) console.log(result)
這兩種方法還是可以獲取對象中symbol對應的值的
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 10 } let result = obj[Object.getOwnPropertySymbols(obj)[0]] console.log(result)
共享符號
上面注冊的都是普通符號,也可以注冊共享符號
普通符號:
let a = Symbol()
共享符號:
let a = Symbol.for()
.for()就代表創建了一個共享的符號,內部參數也是描述信息
let str = Symbol.for("b"); let str2 = Symbol.for("b"); console.log(str == str2);
上面的結果返回的是true,機理是:Symbol.for()定義的符號代表共享符號,如果創建了共享符號,此時就相當於在全局創建了一個符號,此時如果再次創建相同描述的符號,就不會再創建新的了,而是將原來的拋出,所以結果是相等的。
Symbol.keyFor方法
來獲取已經注冊到全局的共享符號的描述信息
let str = Symbol.for("b"); console.log(Symbol.keyFor(str));
Symbol的注意事項
Symbol值不能與其他類型的值進行運算,會報錯:
var str = Symbol('小明'); console.log("我是"+str)
Symbol值可以顯式轉為字符串:
var str = Symbol('小明'); let str2=String(str) let str3=str.toString() console.log(typeof str2) console.log(typeof str3)
Symbol值也可以轉為布爾值,但是不能轉為數值
var num = Symbol(2); let num2=Boolean(num); console.log(typeof num2)
此時改為數值就回報錯
var num = Symbol(2); let num2=Number(num); console.log(typeof num2)