前言:

在做音乐播放器项目时,有一个功能是添加歌曲,很明显,歌曲是不能重复添加的。这时候我想到了 es6 的 Array.from(new Set(arr))去重方法,很明显是不行的,歌曲都是对象,大部分去重方法只能解决基本数据类型的去重,犹记得学 java 时的 equal 方法,比较两个对象是否相等着实折腾了以下当初的我,这篇博文主要是总结一下 js 去重。

  • 方法一:利用 ES6 的 Array.from()/扩展运算符 以及 Set

    Array.from(): The Array.from() method creates a new Array instance from an array-like or iterable object.

    该方法接收两个参数要转换的非数组对象,对每个元素进行处理的方法(可选).在 js 中,有很多类数组对象(array-like object)和可遍历(iterable)对象(包括 ES6 新增的数据结构 Set 和 Map),常见的类数组对象包括 document.querySelectorAll()取到的 NodeList,以及函数内部的 arguments 对象。它们都可以通过 Array.from()转换为真正的数组,从而使用数组的方法。事实上只要对象具有 length 属性,就可以通过 Array.from()转换为真正的数组。

    Set:A collection of unique values that may be of any type.

    Set:一个可以是任何类型的独一无二的值的集合.

function unique(arr) {
  return Array.from(new Set(arr));
}
你也可以这样写:
function unique(arr) {
  return [...new Set(arr)];
}
  • 方法二:遍历数组,建立新数组,利用 indexOf 判断是否存在于新数组中,不存在则 push 到新数组,最后返回新数组

    Determines the index of the specific IThing in the list.

    indexOf() :方法可返回某个指定的字符串值在字符串中首次出现的位置。如果没有则返回-1

function unique(arr) {
  var newArr = [];
  for (var i in arr) {
    if (newArr.indexOf(arr[i]) == -1) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}
  • 方法三:遍历数组,利用 object 对象的 key 值保存数组值,判断数组值是否已经保存在 object 中,未保存则 push 到新数组并用 object[arrayItem]=true 的方式记录保存.
function unique(arr) {
  let hashTable = {};
  let newArr = [];
  for (let i = 0, l = arr.length; i < l; i++) {
    if (!hashTable[arr[i]]) {
      hashTable[arr[i]] = true;
      newArr.push(arr[i]);
    }
  }
  return newArr;
}
  • 方法四:先排序,新数组最后一项为旧数组第一项,每次插入判断新数组最后一项是否与插入项相等
function unique(arr) {
  var newArr = [];
  var end; //end其实就是一道卡
  arr.sort();
  end = arr[0];
  newArr.push(arr[0]);
  for (var i = 1; i < arr.length; i++) {
    if (arr[i] != end) {
      newArr.push(arr[i]);
      end = arr[i]; //更新end
    }
  }
  return newArr;
}
  • 方法五:使用 indexOf 找到的是第一个出现的 index 的特点
function unique(arr) {
  var res = arr.filter(function (item, index, array) {
    return array.indexOf(item) === index;
  });
  return res;
}

以上五种方法都是对于基本数据类型而言,如果换做对象数组就无能为力了,下面是对象数组的去重方法

  • 方法一:利用对象的键名不能重复的特点
function unique(arr) {
  let unique = {};
  arr.forEach(function (item) {
    unique[JSON.stringify(item)] = item; //键名不会重复
  });
  arr = Object.keys(unique).map(function (u) {
    //Object.keys()返回对象的所有键值组成的数组,map方法是一个遍历方法,返回遍历结果组成的数组.将unique对象的键名还原成对象数组
    return JSON.parse(u);
  });
  return arr;
}
/*map方法使用示例:*/
var map = Array.prototype.map;
var a = map.call("Hello World", function (x) {
  return x.charCodeAt(0);
});
// a的值为[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

存在的问题:
{x:1,y:2}与{y:2,x:1}通过 JSON.stringify 字符串化值不同,但显然他们是重复的对象.

  • 方法二:还是利用对象的键名无法重复的特点,必须知道至少一个对象数组中的对象的属性名
var songs = [
  { name: "羽根", artist: "air" },
  { name: "羽根", artist: "air" },
  { name: "晴天", artist: "周杰伦" },
  { name: "晴天", artist: "周杰伦" },
  { artist: "周杰伦", name: "晴天" },
];

function unique(songs) {
  let result = {};
  let finalResult = [];
  for (let i = 0; i < songs.length; i++) {
    result[songs[i].name] = songs[i];
    //因为songs[i].name不能重复,达到去重效果,且这里必须知晓"name"或是其他键名
  }
  //console.log(result);{"羽根":{name:"羽根",artist:"air"},"晴天":{name:"晴天",artist:"周杰伦"}}
  //现在result内部都是不重复的对象了,只需要将其键值取出来转为数组即可
  for (item in result) {
    finalResult.push(result[item]);
  }
  //console.log(finalResult);[{name:"羽根",artist:"air"},{name:"晴天",artist:"周杰伦"}]
  return finalResult;
}

console.log(unique(songs));
原数组(重复).png
result.png
finalResult.png