6. Symbol和Symbol屬性

在ES6之前,語言包含5中類型。字符串,數(shù)字,布爾,undefined, null.
ES6之后,包含了新類型Symbol類型。人們一般通過屬性名來訪問屬性。無論屬性名是什么組成,全部由字符串類型來進(jìn)行訪問。私有名稱是為了讓開發(fā)者創(chuàng)建非字符串的名稱。

1. 創(chuàng)建Symbol

除了Symbol,都有各自字面量的形式。可以通過全局Symbol創(chuàng)建Symbol

// firstName相當(dāng)于一個(gè)變量名稱,不會(huì)轉(zhuǎn)化的變量名稱
let person = {};
let firstName = Symbol(); // firstName就是一個(gè)值,獨(dú)一無二的值。
person[firstName] = "Nicholas";
console.log(person[firstName])
// 在以前的書寫中
let secondName = 'sN'; 
person[secondName] = "Nicholas";
console.log(person[secondName]) // 但是這里會(huì)轉(zhuǎn)化為person.sN

Symbole是原始值。使用new Symbol會(huì)拋出錯(cuò)誤。
Symbole可以接受一個(gè)描述文本。但是這段描述不會(huì)用于屬性訪問。但是建意我們?cè)趧?chuàng)建Symbole對(duì)象增加描述。

// firstName相當(dāng)于一個(gè)變量名稱,不會(huì)轉(zhuǎn)化的變量名稱
let person = {};
let firstName = Symbol('first name'); // firstName就是一個(gè)值,獨(dú)一無二的值。
person[firstName] = "Nicholas";
console.log(person[firstName]) // "Nicholas"
console.log('first name' in person) //  false
console.log(firstName) // Symbol('first name')

Symbol的描述會(huì)被添加在[[Description]]屬性中。只有當(dāng)調(diào)用Symbol的toString方法,描述才會(huì)被打印到日志中。

notice: Symbol是原始值,可以進(jìn)行typeof操作符,返回Symbol類型。我們可以使用typeof查看瀏覽器對(duì)Symbol的支持情況

2. Symbol的使用方法

所有使用計(jì)算屬性名的地方都可以使用Symbol。Symbol可以適用于計(jì)算對(duì)象字面量屬性名、Object.defineProperties()方法中使用

let firstName = Symbol('first name'); 
let person = {[firstName]: 'Nicholas'};
Object.defineProperties(person, firstName, {writeable: false}) // 屬性設(shè)置為只讀
let lastName = Symbol('last name'); 
Object.defineProperties(person, {lastName: {value: 'Zakas', writeable: false}})
console.log(person[firstName], person[lastName]); // Nicholas Zakas

3. Symbol共享體系

我們希望在不同的代碼片段中共享一個(gè)Symbol。這時(shí)候,ES6中提供了隨時(shí)可以訪問的Symbol注冊(cè)表。如果想建立共享的Symbol,要使用Symbol.for()方法。只接受一個(gè)參數(shù),也就是即將創(chuàng)建的symbole的字符串標(biāo)識(shí)符?;蛘呤敲枋?/p>

let uid = Symbol.for(uid);
let obj = {};
obj[uid] = "12345";
console.log(obj[uid]); // "12345"
console.log(uid); // Symbol(uid)

Symbol.for();會(huì)在全局的Symbol注冊(cè)表中搜索鍵為uid的Symbol。如果存在,則返回值,不存在,則進(jìn)行注冊(cè),并且返回新的Symbol。
eg:

let uid = Symbol.for(uid);
let obj = {
  [uid]: "12345";
};
console.log(obj[uid]); // "12345"

let uid2 = Symbol.for(uid);
console.log(uid === uid2); // "12345"
console.log(obj[uid]); // "12345"
console.log(uid2); // Symbol(uid)

還可以使用Symbol.keyFor()在Symbol全局注冊(cè)表中檢索與Symbol有關(guān)的鍵

let uid = Symbol.for(uid);
console.log(Symbol.keyFor(uid)); // uid
let uid2 = Symbol.for(uid);
console.log(Symbol.keyFor(uid2)); // uid
let uid3 = Symbol(uid);
console.log(Symbol.keyFor(uid3)); // undefined 因?yàn)闆]有在全局的注冊(cè)表中注冊(cè)。所以不能搜到。

4. Symbol與類型強(qiáng)轉(zhuǎn)關(guān)系

因?yàn)槠渌禌]有與Symbol邏輯等價(jià)的值,因?yàn)镾ymbol使用不太方便。并且Symbol不能墻磚轉(zhuǎn)化為字符串和數(shù)字類型,可能會(huì)錯(cuò)誤操作對(duì)象屬性,導(dǎo)致結(jié)果不一致。

let uid = Symbol('uid'), desc = String(uid);
console.log(uid); // Symbol('uid') 但是他是string類型的
// 但是不能直接與字符串拼接會(huì)報(bào)錯(cuò)
console.log(uid + ''); // 報(bào)錯(cuò)
// 不能強(qiáng)制轉(zhuǎn)化為數(shù)字類型
console.log(uid/1); // 報(bào)錯(cuò)
// 除了邏輯操作符 為true

5. Symbol屬性檢索

Symbol.keyFor()和Object.getOwnPropotyNames()都可以檢索對(duì)象中所有的屬性名。Symbol.keyFor()返回的是可枚舉的屬性名。Object.getOwnPropotyNames()返回所有屬性名,一律返回。這兩個(gè)都不可支持Symbol屬性。Object.getOwnPropotySymbols()放大來檢索對(duì)象中的Symbol屬性。

let uid = Symbol.for(uid);
let obj = {
 [uid]: "12345";
};
let symbols = Object.getOwnPropotySymbols(obj);
symbols.length // 1
symbols[0] // Symbol(uid)
obj[symbols[0]] //  "12345"
// 對(duì)象中可以繼承Symbol屬性。

6. 通過well-konwn Symbol暴露內(nèi)部操作

6.1 Symbol.hasInstance方法

每個(gè)函數(shù)中都有Symbol.hasInstance方法,用于確定對(duì)象是否為函數(shù)實(shí)例。在Function.prototypes中定義,所有的函數(shù)都繼承了instance的默認(rèn)行為。為了確保Symbol.hasInstance不會(huì)被意外重寫,該方法定義為不可寫,不可配置并且不可枚舉。Symbol.hasInstance只接受被一個(gè)參數(shù),要檢查的值。

obj instance Array;
// 等價(jià)于
Array[Symbol.hasInstance](obj) // Symbol.hasInstance是個(gè)屬性??。?!就像Symbol(123)么???
function MyObject() {
  // 空函數(shù)
}
object.definePropoty(MyObject, Symbol.hasInstance, {
  value: function(v) {
    return false;
  }
})

let obj = new MyObject();
obj.instanceof MyObject // false

建議不要改寫。

6.2 Symbol.isConcatSpreadable屬性

concat使用方法。

let color1 = ['red', 'green'],
let color2 = color1.concat(['blue', 'black']);
let color2 = color1.concat(['yellow'], 'purple');
color2 // ['red', 'green', 'blue', 'black', 'yellow', 'purple']

按照道理,會(huì)直接將參數(shù)一個(gè)一個(gè)的增加在新的數(shù)組中,為什么數(shù)組會(huì)展開呢?因?yàn)樵趈s中,凡是傳入了數(shù)組參數(shù),會(huì)自動(dòng)將他們分割為獨(dú)立元素。Symbol.isConcatSpreadable屬性是一個(gè)Bool值。true表示對(duì)象有l(wèi)ength屬性,和數(shù)字鍵,他的數(shù)字值型屬性值,會(huì)獨(dú)立添加到concat調(diào)用結(jié)果中。Symbol這個(gè)屬性默認(rèn)不會(huì)出現(xiàn)在標(biāo)準(zhǔn)對(duì)象中,是可選屬性。增加對(duì)象的concat()方法調(diào)用。

let collection = {
  0: 'Hello',
  1: 'world',
  length: 2,
  Symbol.isConcatSpreadable: true
}

let msg = ['Hi'].concat(collection);
msg // ['Hi', 'Hello', 'world']
6.3 Symbol.match、Symbol.replace、Symbol.search、Symbol.split屬性

接受正則表達(dá)式作為參數(shù)
.match(regex)判斷正則匹配
.replace(regex, replacement)正則表達(dá)式匹配結(jié)果
.search(regex)進(jìn)行定位
.split(regex)字符串分割
在es6之前是不能對(duì)這幾個(gè)方法進(jìn)行自定義,進(jìn)行字符串匹配。ES6之后用symbol屬性,將regex的元素特性完全暴露。
Symbol.match、Symbol.replace、Symbol.search、Symbol.split屬性表示match(), replace(), search(), split()方法中的第一個(gè)參數(shù)應(yīng)該調(diào)用的正則表達(dá)式參數(shù)的方法。他們被定義在Regex.prototype中。

let regex2 = {
  [Symbol.match]: function (value) {
    return false;
  }
};
'hello'.match(regex2)
6.4 Symbol.toPrimitive方法

js經(jīng)常做隱式轉(zhuǎn)換。比如 == 會(huì)轉(zhuǎn)化為基本類型。但是到底轉(zhuǎn)戶為什么基本類型,在之前是內(nèi)部操作,但是es6之后通過Symbol.toPrimitive暴露出來了,并且可以對(duì)其修改。
Symbol.toPrimitive定義在所有常規(guī)類型的原型上,規(guī)定了轉(zhuǎn)化規(guī)則。當(dāng)轉(zhuǎn)化是會(huì)進(jìn)行調(diào)用,并傳入提示性參數(shù)。這個(gè)參數(shù)有3種可能。number string default

number :調(diào)用valueof()方法,返回基本類型,返回它。否則調(diào)用toString()方法返回,否則拋出錯(cuò)誤
string :調(diào)用toString()方法,返回基本類型,返回它。否則調(diào)用valueof()方法返回,否則拋出錯(cuò)誤
default : 多數(shù)在== + 運(yùn)算符或者傳遞單一參數(shù)給date構(gòu)造器被使用。

多數(shù)情況下,常規(guī)對(duì)象等價(jià)于數(shù)值模式????Date類型除外,使用string模式

function Templerature(value) {
  this.value = value;
}
Templerature.prototype[Symbol.toPrimitive] = function(hint) {
  switch (hint) {
    case 'string': 
      return this.value+'!'
  }
}
let tmp = new Templerature(32);
String(tmp)
"32!"
6.5 Symbol.toStringTag屬性
function isArray(value) {
 return Object.prototype.toString.call(value) === "[object Array]";
}
console.log(isArray([])); // true

ES6通過 Symbol.toStringTag 定義了 Object.prototype.toString.call() 被調(diào)用時(shí)應(yīng)當(dāng)返回什么值。對(duì)于數(shù)組來說,在Symbol.toStringTag 屬性中存儲(chǔ)了 "Array" 值,于是該函數(shù)的返回值也就是 "Array" 。

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]"

Symbol.toStringTag 的返回值在調(diào)用 me.toString() 的時(shí)候也會(huì)被使用。

function Person(name) {
  this.name = name;
}
Person.prototype[Symbol.toStringTag] = "Person";
Person.prototype.toString = function() {
return this.name;
};

let me = new Person("Nicholas");
console.log(me.toString()); // "Nicholas"
console.log(Object.prototype.toString.call(me)); //  "[object Person]"
6.6 Symbol.unscopables屬性

with語句的支持。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原始類型:Symbol,用于創(chuàng)建必須通過Symbol才能引用的屬性,提供了一些私有性和不易覆蓋的特性。 1、創(chuàng)建S...
    Zip_Wang閱讀 986評(píng)論 0 50
  • 回憶一下JS中的原始類型:字符串型、數(shù)字型、布爾型、null和undefined。 ES6中引入了第6種原始類型:...
    ___Jing___閱讀 8,816評(píng)論 2 10
  • 原創(chuàng)文章&經(jīng)驗(yàn)總結(jié)&從校招到A廠一路陽光一路滄桑 詳情請(qǐng)戳www.codercc.com 主要知識(shí)點(diǎn):創(chuàng)建符號(hào)值、...
    你聽___閱讀 970評(píng)論 0 1
  • 概述 ES5 的對(duì)象屬性名都是字符串,這容易造成屬性名的沖突。比如,你使用了一個(gè)他人提供的對(duì)象,但又想為這個(gè)對(duì)象添...
    米諾zuo閱讀 425評(píng)論 0 0
  • 本人是android開發(fā)的,由于最近React Native的火熱,再加上自己完全不懂JS的語法,俗話說的好"落后...
    Bui_vlee閱讀 355評(píng)論 0 0

友情鏈接更多精彩內(nèi)容