創建符號值
Symbol沒有字面量形式,這在JS的基本類型中是獨一無二的.可以用全局函數來創建符號值
let firstName=Symbol();
let person={};
person[firstName]='Polo';
console.log(person[firstName]); // 'Polo'
//es6擴展了typeof運算符,可以識別symbol基本類型
console.log(typeof firstName); // 'symbol;
符號值是基本類型,因此調用new Symbol()會拋出錯誤
共享符號值
使用Symbol.for方法,創建共享符號值,該方法僅接受當字符串類型的參數,作為目標符號值得標識符,同時此參數也會成為該符號的描述信息
let uid=Symbol.for('uid');
let obj={};
obj[uid]=12334;
console.log(obj[uid]); // 12334
console.log(uid); // symbol(uid)
Symbol.for() 方法首先會搜索全局符號注冊表,看是否存在一個鍵值為 "uid" 的符號值。若是,該方法會返回這個已存在的符號值;否則,會創建一個新的符號值,并使用該鍵值將其記錄到全局符號注冊表中,然后返回這個新的符號值。這就意味著此后使用同一個鍵值去調用 Symbol.for() 方法都將會返回同一個符號值,就像下面這個例子:
let uid=Symbol.for('uid');
let obj={};
obj[uid]=12334;
let uid2=Symbol.for('uid');
console.log(uid===uid2); //true
console.log(obj[uid2]); //12334
console.log(uid2); //symbol(uid)
Symbol.keyFor方法,在全局符號注冊表中根據符號值檢索出對應的鍵值
let uid = Symbol.for("uid");
console.log(Symbol.keyFor(uid)); // "uid"
檢索符號屬性
Object.keys()返回對象所有可枚舉屬性名稱
Object.getOwnPropertyNames() 返回所有屬性名稱而無視其是否可枚舉
然而以上兩個方法都不能返回符號類型的屬性,
ES6中新增Object.getOwnPropertySymbols(),返回符號類型的屬性
ES6知名符號
ES6 定義了“知名符號”來代表 JS 中一些公共行為,而這些行為此前被認為只能是內部操作。每一個知名符號都對應全局 Symbol 對象的一個屬性
這些知名符號是:
- Symbol.hasInstance :供 instanceof 運算符使用的一個方法,用于判斷對象繼承關系。
- Symbol.isConcatSpreadable :一個布爾類型值,在集合對象作為參數傳遞給
- Array.prototype.concat() 方法時,指示是否要將該集合的元素扁平化。
- Symbol.iterator :返回迭代器(參閱第七章)的一個方法。
- Symbol.match :供 String.prototype.match() 函數使用的一個方法,用于比較字符串。
- Symbol.replace :供 String.prototype.replace() 函數使用的一個方法,用于替換子字符串。
- Symbol.search :供 String.prototype.search() 函數使用的一個方法,用于定位子字符串。
- Symbol.species :用于產生派生對象(參閱第八章)的構造器。
- Symbol.split :供 String.prototype.split() 函數使用的一個方法,用于分割字符串。
- Symbol.toPrimitive :返回對象所對應的基本類型值的一個方法。
- Symbol.toStringTag :供 String.prototype.toString() 函數使用的一個方法,用于創建對象的描述信息。
- Symbol.unscopables :一個對象,該對象的屬性指示了哪些屬性名不允許被包含在 with 語句中。
Symbol.hasInstance
用于判斷指定對象是否為本函數的一個實例。這個方法定義在 Function.prototype 上,因此所有函數都繼承了面對 instanceof 運算符時的默認行為。 Symbol.hasInstance 屬性自身是不可寫入、不可配置、不可枚舉的,從而保證它不會被錯誤地重寫。
obj instanceof Array;
//等價于
Array[Symbol.hasInstance](obj);
ES6 從本質上將 instanceof 運算符重定義為上述方法調用的簡寫語法.
例如,假設你想定義一個函數,使得任意對象都不會被判斷為該函數的一個實例,你可以采用硬編碼的方式讓該函數的 Symbol.hasInstance 方法始終返回 false
function MyObj(){
}
Object.defineProperty(MyObj,Symbol.hasInstance,{
value:function(v){
return false;
}
});
let obj=new MyObj();
console.log(obj instanceof MyObj); // false
Symbol.isConcatSpreadable
該屬性是一個布爾類型的屬性,它表示目標對象擁有長度屬性與數值類型的鍵、并且數值類型鍵所對應的屬性值在參與 concat() 調用時需要被分離為個體。它只出現在特定類型的對象上,用來標示該對象在作為 concat() 參數時應如何工作,從而有效改變該對象的默認行為。
let collection = {
0: "Hello",
1: "world",
length: 2,
[Symbol.isConcatSpreadable]: true
};
let messages = [ "Hi" ].concat(collection);
console.log(messages.length); // 3
console.log(messages); // ["hi","Hello","world"]
Symbol.toPrimitive
該屬性規定了在對象被轉換為基本類型值的時候會發生什么。
當需要轉換時, Symbol.toPrimitive 會被調用,并按照規范傳入一個提示性的字符串參數。該參數有 3 種可能:
- 當參數值為 "number" 的時候, Symbol.toPrimitive 應當返回一個數值;
- 當參數值為 "string" 的時候,應當返回一個字符串;
- 而當參數為 "default" 的時候,對返回值類型沒有特別要求。
function Temperature(degrees) {
this.degrees = degrees;
}
Temperature.prototype[Symbol.toPrimitive] = function(hint) {
switch (hint) {
case "string":
return this.degrees + "\u00b0"; // 溫度符號
case "number":
return this.degrees;
case "default":
return this.degrees + " degrees";
}
};
let freezing = new Temperature(32);
console.log(freezing + "!"); // "32 degrees!"
console.log(freezing / 2); // 16
console.log(String(freezing)); // "32°"
Symbol.toStringTag
該屬性定義了Object.prototype.toString.call()被調用時應該返回什么值,同樣可以在自定義對象上定該屬性值.
function Person(name) {
this.name = name;
}
Person.prototype[Symbol.toStringTag] = "Person";
let me = new Person("Nicholas");
console.log(me.toString()); // "[object Person]"
console.log(Object.prototype.toString.call(me)); // "[object Person]"