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

前言

随着2020年的带来,JS基本类型也增加到了7种,Bigint这个玩意说起来也挺好理解的,再加上undefined, null, string, number, boolean,相对于引用类型,都是比较好明白的。哎等会,好像少了一个,Symbol这个ES6新增的东西到底有啥用呢?
ES6前没有实现集合和字典类型确实产生了一些不便,因此ES6中补上了这两个东西,可是呢由于JS对象的特殊性,这两个在实际开发中也没有得到太多的应用,虽说是比Symbol好一点。

你在开发中用过Symbol么

对于还没接触工作,各种玩具工作,抄人代码的我来说,Symbol这玩意我真没用过。看看它同时代的…,解构赋值,箭头函数,Promise,已经可以说是用到烂了,那么这个东西到底有什么用呢?

大家对Symbol有着些许了解的人可能知道:

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

这段代码有啥用我也不解释了,这是我对Symbol的唯一印象,甚至当初我学Immer的时候第一时间就想到了这个,虽然好像没啥关系。

Symbol

Symbol,中文常称为符号,先看几个重要的特性:

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

Symbol.for是可共享,在创建的时候会检查全局是否寻在这个key的symbol.如果存在就直接返回这个symbol,如果不存在就会创建,并且在全局注册。

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

keyFor,获取for创建的共享Symbol。别的无法获取。

当然还有很多API,我们稍后再说,毕竟这篇文章主要是想让大家知道,Symbol到底能干什么。

Symbol用来干啥

下面内容参考自此文

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方法也是一样的三个传参,这里就不演示了。

发布了346 篇原创文章 · 获赞 330 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43870742/article/details/104001398