一文帶你看懂ES6中的Set,Map,Symbol

前言

隨着2020年的帶來,JS基本類型也增長到了7種,Bigint這個玩意提及來也挺好理解的,再加上undefined, null, string, number, boolean,相對於引用類型,都是比較好明白的。哎等會,好像少了一個,Symbol這個ES6新增的東西到底有啥用呢?
ES6前沒有實現集合和字典類型確實產生了一些不便,所以ES6中補上了這兩個東西,但是呢因爲JS對象的特殊性,這兩個在實際開發中也沒有獲得太多的應用,雖然說是比Symbol好一點。前端

你在開發中用過Symbol麼

對於還沒接觸工做,各類玩具工做,抄人代碼的我來講,Symbol這玩意我真沒用過。看看它同時代的…,解構賦值,箭頭函數,Promise,已經能夠說是用到爛了,那麼這個東西到底有什麼用呢?python

你們對Symbol有着些許瞭解的人可能知道:es6

> let a = Symbol('1')
undefined
> let b = Symbol('1')
undefined
> a===b
false

這段代碼有啥用我也不解釋了,這是我對Symbol的惟一印象,甚至當初我學Immer的時候第一時間就想到了這個,雖然好像沒啥關係。web

Symbol

Symbol,中文常稱爲符號,先看幾個重要的特性:數組

> a
Symbol(1)
> let b = Symbol.for('1')
undefined
> b
Symbol(1)
> a===b
true

Symbol.for是可共享,在建立的時候會檢查全局是否尋在這個key的symbol.若是存在就直接返回這個symbol,若是不存在就會建立,而且在全局註冊。svg

> Symbol.keyFor(a)
'1'
> c = Symbol('1')
Symbol(1)
> Symbol.keyFor(c)
undefined

keyFor,獲取for建立的共享Symbol。別的沒法獲取。函數

固然還有不少API,咱們稍後再說,畢竟這篇文章主要是想讓你們知道,Symbol到底能幹什麼。spa

Symbol用來幹啥

下面內容參考自此文debug

var myObj = {};
var fooSym = Symbol('foo');
var otherSym = Symbol('bar');
myObj['foo'] = 'bar';
myObj[fooSym] = 'baz';
myObj[otherSym] = 'bing';
assert(myObj.foo === 'bar');
assert(myObj[fooSym] === 'baz');
assert(myObj[otherSym] === 'bing');

這個例子仍是很好理解的,也就是說Symbol都是惟一的,固然除了Symbol.for()。所以假定你有一個日誌庫,該庫包含了多個日誌級別,例如 logger.levels.DEBUG、logger.levels.INFO、logger.levels.WARN 等等。在 ES5 中,你經過字符串或者整型設置或者判斷級別:logger.levels.DEBUG === ‘debug’、logger.levels.DEBUG === 10。這些方式都不是理想方式,由於它們不能保證級別取值惟一,可是Symbol能夠知足這個要求。日誌

先寫到這裏,之後使用到了在更新例子吧

Set

集合在python中早就存在了,當時作題的時候以爲有個這麼個玩意是真的方便,因此開始轉前端時,JS中這個還要New的東西讓我以爲是真的麻煩,後來開發過程當中對於集合的須要並無那麼迫切,也就漸漸忘記了。此次刷題,突然發現原來集合的方法還挺多,並且仍是有一些坑的。

let req = new Set([12,2,3])
req.forEach((item,index,ss) => console.log(item, index,ss))

sentry-5.7.1.min.js:2 12 12 Set(3) {12, 2, 3}
sentry-5.7.1.min.js:2 2 2 Set(3) {12, 2, 3}
sentry-5.7.1.min.js:2 3 3 Set(3) {12, 2, 3}

map是沒有辦法遍歷集合類型的,forEach則能夠,有趣的是forEach的傳值,key,value是相等的,這個咱們能夠理解,可是沒有索引,同時第三個值表明了集合自己就有些不知所云了。

同時咱們要知道的是Set中的子項是經過Object.is進行判斷的,他與全等的區別不大,有兩點:

-0 === 0
true
Object.is(-0, 0)
false
NaN === NaN
false
Object.is(-NaN, NaN)
true

然而有趣的是!Set中的-0和0也是true,嗯還有有點奇怪。

同時Set與數組之間能夠經過延展操做展開。

qq.add({})
Set(3) {3, 2, {}}
qq.add({})
Set(4) {3, 2, {}, {}}

能夠看到,和咱們想象的不同,‘{}’並不會被轉化成’[Object, Object]’。

Map

說完了奇怪的Set,讓咱們看看Map,Map和對象最大的不一樣應該就是鍵能夠是任意類型:

> let a = {a:1}
undefined
> let b = new Map()
undefined
> b.set(a,2)
Map { { a: 1 } => 2 }
> let c = {}
undefined
> c[a] = 2
2
> c
{ '[object Object]': 2 }

有趣的是Map的初始化,照理說應該傳個對象啥的,它穿的是特殊的對象–數組,同時數組的子項也得是數組:

> let a = new Map([[1,2],['a','b']])
undefined
> a
Map { 1 => 2, 'a' => 'b' }

與前者相同,它的forEeah方法也是同樣的三個傳參,這裏就不演示了。