Set

Set 对象是一种新数据结构,允许你存储任何类型的唯一值,无论是原始值或者是对象引用。

我们可以从给定数组创建一个新的 Set(),以丢弃重复的值。然后使用扩展运算符(...)将其转换回数组。

const arr = [1, 2, 2, '1', null, '', undefined, NaN, NaN, true, false]

const unique = arr => [...new Set(arr)]
unique(arr) // [1, 2, "1", null, "", undefined, NaN, true, false]

注意,如果数值中存的是对象,值相同,但他们引用的是不同的内存地址,他会认为每个对象都是唯一的:

[...new Set([{ a: 1 }, { a: 1 }])] // [{a: 1}, {a: 1}]

// 你可以改成如下
let obj = { a: 1 }
[...new Set([obj, obj])] // [{ a: 1 }]

Set 除了和扩展运算符配合,还可以和 Array.form() 一起使用:

let unique = (arr) => Array.from(new Set(arr))

unique(arr) // [1, 2, "1", null, "", undefined, NaN, true, false]

Map

创建一个空 Map 数据结构,使用 Array.prototype.filter() 和 创建一个只包含唯一值的新数组。

const unique = arr => {
  const seen = new Map()
  return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}

unique(arr) // [1, 2, "1", null, "", undefined, NaN, true, false]

Array.prototype.filter()

使用 Array.prototype.filter() 创建一个只包含唯一值的新数组。

let unique = arr => 
  arr.filter((item, index, arr) => arr.indexOf(item) === index)

unique(arr) // [1, 2, "1", null, "", undefined, true, false]

注意:该方法直接把 NaN 全局过滤了。

Array.prototype.includes()

let unique = arr => {
  let newArr = []
  arr.map(item => !newArr.includes(item) && newArr.push(item))
  return newArr
}
  
unique(arr) // [1, 2, "1", null, "", undefined, NaN, true, false]

也可以使用 Array.prototype.indexOf() 进行判断,但是存在着一个问题,该方法无法判断数组中是否含有 NaN

let unique = arr => {
  let newArr = []
  arr.map(item => newArr.indexOf(item) == -1 && newArr.push(item))
  return newArr
}

unique(arr) //  [1, 2, "1", null, "", undefined, NaN, NaN, true, false]

Array.prototype.reduce()

Array.prototype.reduce() 方法对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果组合成数组返回。

let unique = arr =>
  arr.reduce(
    (unique, item) => (unique.includes(item) ? unique : [...unique, item]),
    []
  )

unique(arr) // [1, 2, "1", null, "", undefined, NaN, true, false]

Object.hasOwnProperty()

利用 Object.hasOwnProperty 判断是否存在对象属性

const unique = arr => {
  var obj = {}
  return arr.filter((item, index, arr) => {
    return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  })
}

unique(arr) // [1, 2, "1", null, "", undefined, NaN, true, false]

Object 键值对

利用对象键值对不能相同名来去重

const unique = arr => {
  var obj = {}
  arr.forEach(value => {
    obj[value] = 0
  })
  return Object.keys(obj)
}

unique(arr) // ["1", "2", "null", "", "undefined", "NaN", "true", "false"]

注意两个问题

  • 数组中的任何类型都会转为字符串类型。
  • 当数组中存在相同值不同类型的数据时,会去掉其中一个。如数值 1 和字符串 '1',会去掉其中一个。