一念之差,錯失良機!淺談基礎類型之Symbol,給你的筆試多加一分~

前言

12月初的時候,我打算將阮大大的《ECMAScript6 入門》作一個筆記,順帶做爲參考的,可是這個文章已經在11號左右的時候流產了。爲何呢?一個是由於最近主管給分配了任務,沒啥時間作;還有一個緣由就是:尼瑪看不懂了啊!!!javascript

最近事情少了,回過頭繼續學習,看到一個有意思的玩意:Symboljava

ES6 引入了一種新的原始數據類型Symbol,表示獨一無二的值。es6

原始數據類型??這讓我想起來以前的一道筆試題:JavaScript數據類型有哪些?面試

當時我寫的是:undefined、null、number、string、boolean、Object。面試官問了我一句,數據類型就是這些了嗎?我內心有個Symbol的印象,可是當面試官繼續問做用的時候我啞然了,由於個人確沒了解過具體這東西是幹嗎的呀?因而面試官給我講起了Symbol的相關知識:數組

概述

ES5 的對象屬性名都是字符串,這容易形成屬性名的衝突。好比,你使用了一個他人提供的對象,但又想爲這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法產生衝突。若是有一種機制,保證每一個屬性的名字都是獨一無二的就行了,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol的緣由。函數

基本用法

let s = Symbol();

typeof s // => "symbol" 
複製代碼

這好像和之前生成對象的寫法不太同樣,沒有用new命令,你問我爲何?廢話用new命令那不就是對象了嗎?Symbol是原始數據類型呀!和對象是並列關係~學習

有的童鞋會問,用Symbol()生成的話,很不利於閱讀呀,誰知道這個Symbol是幹嗎的呢?不要緊,Symbol已經幫咱們想好了解決辦法:ui

Symbol函數能夠接受一個字符串做爲參數,表示對 Symbol 實例的描述,主要是爲了在控制檯顯示,或者轉爲字符串時,比較容易區分。this

let s1 = Symbol('s1'); // => Symbol(s1)
let s2 = Symbol('s2'); // => Symbol(s2)
let s3 = Symbol('s1'); // => Symbol(s1)
複製代碼

這時候又有好奇寶寶要問了,加上了描述,這兩個Symbol值是否是就變成同樣的了?spa

s1 == s3 // => false
s1 === s3 // => false
複製代碼

不論是==仍是===,返回值都是false,這說明:

Symbol函數的參數只是表示對當前 Symbol 值的描述,所以相同參數的Symbol函數的返回值是不相等的。

類型轉換

Symbol 值不能與其餘類型的值進行運算,會報錯。

let s = Symbol('s');
s + ' is a Symbol!' // => index.js:13 Uncaught TypeError: Cannot convert a Symbol value to a string
複製代碼

Symbol 值能夠顯式轉爲字符串。

let s = Symbol('s');
s.toString(); // => Symbol(s)
s.toString() + ' is a Symbol!' // => Symbol(s) is a Symbol!
複製代碼

能夠看到這時候能夠和字符串相加了。

Symbol 值也能夠轉爲布爾值,可是不能轉爲數值。

let s = Symbol();
Boolean(s); // => true
!s // => false

Number(s); // => TypeError: Cannot convert a Symbol value to a number
Number(s) + 2; // => TypeError: Cannot convert a Symbol value to a number
複製代碼
  • 上面給Symbol添加的描述,要想獲取的話只能經過toString()顯式轉換,比較不方便

ES2019 提供了一個實例屬性description,直接返回 Symbol 的描述。

let s = Symbol('this is a Symbol');
s.description // => this is a Symbol
複製代碼

Symbol用法

Symbol 值能夠做爲標識符,用於對象的屬性名。

有人問了,我用字符串作屬性名,又快又方便,爲何要用Symbol呢?

這個問題問的好,不少學習不細心(可能只有我一個)的童鞋就有這樣的疑問!

咱們來看看上面對Symbol的介紹:

ES6 引入了一種新的原始數據類型Symbol,表示獨一無二的值。

是的,獨一無二,你有沒有在開發中遇到變量名相似的狀況,苦於不知道怎麼區分?你是否在操做其餘同事編寫的對象的時候,懼怕本身添加的變量名將其餘變量覆蓋,或者被其餘變量覆蓋呢?這時候你就須要一個Symbol值來續命(+ 1s)了!

做爲屬性名使用

let s = Symbol();
// 第一種寫法
let obj = {
    [s]: 'hello Symbol'
}

// 第二種寫法
let obj = {};
obj[s] = 'hello Symbol'

// 第三種寫法
let obj = {};
Object.defineProperty(obj,s,{value:'hello Symbol'})

// 以上三種寫法的結果都是
obj[s]; // => hello Symbol
複製代碼

注意

  • Symbol值做爲屬性名,讀取時不能使用點運算符
  • 在對象內部使用Symbol值做爲屬性名時,必須放在方括號中

做爲屬性名時的遍歷

Symbol 做爲屬性名,遍歷對象的時候,該屬性不會出如今for...in、for...of循環中,也不會被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。

for大法都沒法遍歷?那是否是私有屬性?回答是:NO,對象提供了一個Object.getOwnPropertySymbols()方法用於獲取對象內全部Symbol屬性名,返回一個數組

實例:消除魔術字符串

消除魔術字符串

Symbol.for()

有時,咱們但願從新使用同一個 Symbol 值,Symbol.for()方法能夠作到這一點。

let s1 = Symbol.for('s');
let s2 = Symbol.for('s');
s1 === s2; // => true
複製代碼

那麼問題來了:SymbolSymbol.for的區別是什麼呢?

前者會被登記在全局環境中供搜索,後者不會。Symbol.for()不會每次調用就返回一個新的 Symbol 類型的值,而是會先檢查給定的key是否已經存在,若是不存在纔會新建一個值。

面試結束

到這個時候面試已經結束

但我感受事情可能並無想象中的那麼簡單

內置的Symbol值

回看一下阮大大的教程最後:

除了定義本身使用的 Symbol 值之外,ES6 還提供了 11 個內置的 Symbol 值,指向語言內部使用的方法。

Symbol.hasInstance

對象的Symbol.hasInstance屬性,指向一個內部方法。當其餘對象使用instanceof運算符,判斷是否爲該對象的實例時,會調用這個方法。

function fn(){
    
}
let ins = new fn();
ins instanceof fn; // => true
fn[Symbol.hasInstance](ins); // => true
複製代碼

Symbol.isConcatSpreadable

對象的Symbol.isConcatSpreadable屬性等於一個布爾值,表示該對象用於Array.prototype.concat()時,是否能夠展開。

let arr1 = ['a','b'];
let arr2 = ['c','d'];
arr1.concat(arr2); // => ['a','b','c','d']

arr2[Symbol.isConcatSpreadable] = false;
arr1.concat(arr2); // => ['a','b',['c','d']]
複製代碼

Symbol.species、Symbol.match、Symbol.relpace、Symbol.search、Symbol.split.....

這些咱也不知道有啥用,咱也看不懂,等後面有閒工夫再去研究吧~

相關文章
相關標籤/搜索