重学JS | Set和Map是如何过滤重复值的?

1,139 阅读2分钟

这是我参与更文挑战的第22天,活动详情查看:更文挑战

[重学JavaScript系列文章连载中...]

背景

ES6的Set集合是一种包含多个非重复值的有序列表,值与值如果相同,则会自动过滤重复值。它可以用来过滤数组中的重复元素,但是Set集合并不是数组的子类,所以不能通过索引直接访问集合中的值,只能通过has()检测元素是否在集合中,或者通过size()检测集合中值的数量,同时它支持forEach()或者遍历器来处理集合中的每个值。

Map是多个键值对组成的有序集合,键名支持任意数据类型,同时Map也是不允许存在重复值,对键名会存在过滤。

那Set和Map是怎么过滤键值对的?我们通常比较值,有两种方式用“==”或者“===”。

附:对Set不熟的可以前往改文字看看

ES6既有Set,为何还要有Weak Set集合?

==运算符

“==”运算符在判断相等时,如果两边的变量不是同一类型,会进行强制转换。这会导致(""==false)为true。

===运算符

“===”运算符只有在无需类型转换运算数就相等的情况下,才返回true。其将+0和-0视为相等,Number.NaN与NaN视为不相等。

学过Set和Map我们都知道,在这两集合中1和“1”是不会被过滤,且NaN值会被过滤,只允许存在一个。那么上述两种运算符是不符合了。

Object.is()

该用于判断两个值是否为同一值。而Set和Map集合便是用此方法进行判断,它的用法如下:

// value1:被比较的第一个值 value2:被比较的第二个值
Object.is(value1,value2)

Object.is()判断两个值是否同一值的规则如下:

  1. 都是undefined

  2. 都是null

  3. 都是true或false

  4. 都是相同长度的字符串且相同字符串顺序排列

  5. 都是相同对象(对象同一个引用)

  6. 都是数字且

    1. 都是+0

    2. 都是-0

    3. 都是NaN

    4. 或都是非零而且非NaN且为同一个值

看完它两值相等的规则,很好的满足Set和Map集合过滤重复值的需求点。

Polyfill

最后实现下Object.is的Polyfill。

if(!Object.is){
   Object.is = function(x,y){
    if(x===y){
      // 满足上述的1~6.2和6.4点的判断
      // 1/x === 1/y :判断的是+0和-0
      return x!==0 || 1/x === 1/y
    }else{
      // 此处判断的是x和y是否都为NaN
      return x!==x && y!==y
    }
  }
}

至此关于类型相等可以灵活运用了。