乐趣区

关于javascript:跟着大佬学JavaScript之数组去重结果对比

前言

数组去重在面试和工作中都是比拟容易见到的问题。

这篇文章次要是来测试多个办法,对上面这个数组的去重后果进行剖析探讨。如果有不对的中央,还请大家指出。

 const arr = [1, 1, "1", "1", 0, 0, "0", "0", true, false, "true", "false", "a", "A", undefined, undefined, "undefined", null, null, 'null', NaN, NaN, +0, -0, new String("1"), new String("1"), Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], [] ];

非凡类型

console.log(1 == "1"); // true
console.log(1 === "1"); // false

console.log(0 == "0"); // true
console.log(0 === "0"); // false

console.log(0 == +0); // true
console.log(0 === +0); // true

console.log(0 == -0); // true
console.log(0 === -0); // true

console.log(+0 == -0); // true
console.log(+0 === -0); // true

console.log(0 == false); // true
console.log(0 === false); // false

console.log(0 == undefined); // false
console.log(0 === undefined); // false

console.log(0 == null); // false
console.log(0 === null); // false

console.log(1 == true); // true
console.log(1 === true); // false

console.log(undefined == null); // true
console.log(undefined === null); // false

console.log(NaN == NaN); // false
console.log(NaN === NaN); // false

console.log(new String("1") == new String("1")); // false
console.log(new String("1") === new String("1")); // false
Object.prototype.toString.call(new String('1')) // '[object String]'


console.log(/a/ == /a/); // false
console.log(/a/ === /a/); // false
Object.prototype.toString.call(/a/); //'[object RegExp]'


console.log(Symbol(1) == Symbol(1)); // false
console.log(Symbol(1) === Symbol(1)); // false

console.log({} == {}); // false
console.log({} === {}); // false

console.log([] == []); // false
console.log([] === []); // false

接下来,咱们看看上面多个去重办法,对以上非凡类型的去重成果。

代码一(暴力解法)

// 暴力解法一

function unique(array) {if (!Array.isArray(array)) {console.log("type error!");
      return;
    }
    const res = [array[0]];
    let arrLen = array.length;
    let resLen = res.length;
    
    for (let i = 0; i < arrLen; i++) {
      let flag = true;
      for (let j = 0; j < resLen; j++) {if (array[i] === res[j]) {
          flag = false;
          break;
        }
      }
      if (flag) {res.push(array[i]);
        resLen = res.length;
      }
    }
    return res;
}
// [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入后果阐明:

  1. 去重+0-00
  2. NaN不去重
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. Symbol(1)不去重

暴力解法,简略易了解,兼容性好。去重后果如上所示。

代码二(ES6)

// ES6 Array.from + Set 办法一
function unique(array) {if (!Array.isArray(array)) {console.log('type error!')
      return
    }
    return Array.from(new Set(array))
}

// ES6 点运算 + Set 办法二
function unique1(array) {if (!Array.isArray(array)) {console.log('type error!')
      return
    }
    return [...new Set(arr)]
}

// ES6 箭头函数 + 点运算 + Set 办法三
const unique2 = (array) => {if (!Array.isArray(array)) {console.log('type error!')
      return
    }
    return [...new Set(arr)]
}

// ES6 Map + ES5 filter  办法四
function unique3(array) {if (!Array.isArray(array)) {console.log('type error!')
      return
    }
    const seen = new Map()
    return array.filter((a) => !seen.has(a) && seen.set(a, 1))
}

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入后果阐明:

  1. 去重+0-00
  2. 去重NaN
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. Symbol(1)不去重

代码三(indexOf + forEach)

利用 indexOf 检测元素在新数组是否存在

// indexOf + forEach 利用 indexOf 检测元素在新数组是否存在
function unique(array) {if (!Array.isArray(array)) {console.log('type error!')
        return
    }
    const newArr = [];
    array.forEach((el) => {if (newArr.indexOf(el) === -1) {newArr.push(el);
      }
    });
    return newArr;
}

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入后果阐明:

  1. 去重+0-00
  2. NaN不去重
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. Symbol(1)不去重

代码四(indexOf + filter)

利用 indexOf 检测元素在数组中第一次呈现的地位是否和元素当初的地位相等

// indexOf + forEach 利用 indexOf 检测元素在新数组是否存在
function unique(array) {if (!Array.isArray(array)) {console.log('type error!')
        return
    }
    return array.filter((item, index) => {return array.indexOf(item) === index;
    });
}

console.log([NaN].indexOf(NaN)); // -1

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入后果阐明:

  1. 去重+0-00
  2. 两个 NaN 都会被删除
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. Symbol(1)不去重

重点:

console.log([NaN].indexOf(NaN)); // -1

代码五(sort 排序,不反对 Symbol)

sort()办法次要是用于对数组进行排序,默认状况下该办法是将数组元素转换成字符串,而后依照 ASC 码进行排序

// sort()办法不反对 Symbol,Symbol 不反对转换成字符串
function unique(array) {if (!Array.isArray(array)) {console.log("type error!");
      return;
    }
    const sortArr = array.sort();
    const newArr = [];
    sortArr.forEach((el, i) => {if (sortArr[i] !== sortArr[i - 1]) {newArr.push(el);
      }
    });
    return newArr;
}

输入:

[[], [], /a/, /a/, 0, "0", 0, 1, "1", String {'1'}, String {'1'}, "A", NaN, NaN, {}, {}, "a", false, "false", null, "null", true, "true", "undefined", undefined]

输入后果阐明:

  1. +0-00"0"地位不同会导致去重不了
  2. NaN不去重
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. sort()办法不反对解决含有 Symbol 的数组

代码六(includes)

利用 includes()办法查看新数组是否蕴含原数组的每一项

// 利用 includes()办法查看新数组是否蕴含原数组的每一项
function unique(array) {if (!Array.isArray(array)) {console.log("type error!");
      return;
    }
    
    const newArr = [];
    array.forEach((el) => {newArr.includes(el) ? newArr : newArr.push(el);
    });
    return newArr;
}

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入后果阐明:

  1. 去重+0-00
  2. 去重NaN
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. Symbol不去重

代码七(includes+reduce)

利用 includes()办法查看新数组是否蕴含原数组的每一项

// 利用 includes()办法查看新数组是否蕴含原数组的每一项
function unique(array) {if (!Array.isArray(array)) {console.log("type error!");
      return;
    }
    
    return array.reduce((pre, cur) => {!pre.includes(cur) && pre.push(cur);
      return pre;
    }, []);
}

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []]

输入后果阐明:

  1. 去重+0-00
  2. 去重NaN
  3. 对象 new String("1")/a/{} 不去重
  4. 数组 [] 不去重
  5. Symbol不去重

代码八(对象 key)

利用了对象的 key 不能够反复的个性来进行去重

// 利用了对象的 key 不能够反复的个性来进行去重
function unique(array) {if (!Array.isArray(array)) {console.log("type error!");
      return;
    }
    
    const obj = {};
    const newArr = [];
    array.forEach((val) => {if (!obj[typeof val + JSON.stringify(val)]) {
        // 将对象序列化之后作为 key 来应用
        obj[typeof val + JSON.stringify(val)] = 1;
        newArr.push(val);
      }
    });
    return newArr;
}

输入:

[1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, Symbol(1), {}, []]

输入后果阐明:

  1. 去重+0-00
  2. 去重NaN
  3. 去重对象 new String("1"){}; 两个/a/ 全副被删除了
  4. 去重数组[]
  5. 去重Symbol

将不该去重的 Symbol 去重了; 将两个 /a/ 全副删除了

总结

办法 后果 阐明
for 循环暴力解法 [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] 1. 去重 +0、-0、0;2.NaN 不去重;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.Symbol(1)不去重;
ES6 解法 [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], [] 1. 去重 +0、-0、0;2. 去重 NaN;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.Symbol(1)不去重;
indexOf + forEach [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] 1. 去重 +0、-0、0;2.NaN 不去重;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.Symbol(1)不去重;
indexOf + filter [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] 1. 去重 +0、-0、0;2. 两个 NaN 都会被删除;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.Symbol(1)不去重;
sort 排序,不反对 Symbol [[], [], /a/, /a/, 0, "0", 0, 1, "1", String {'1'}, String {'1'}, "A", NaN, NaN, {}, {}, "a", false, "false", null, "null", true, "true", "undefined", undefined] 1.+0、-0、0、”0″ 地位不同会导致去重不了 2.NaN 不去重;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.sort()办法不反对解决含有 Symbol 的数组;
includes [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] 1. 去重 +0、-0、0;2. 去重 NaN;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.Symbol(1)不去重;
includes+reduce [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, String {'1'}, Symbol(1), Symbol(1), {}, {}, /a/, /a/, [], []] 1. 去重 +0、-0、0;2. 去重 NaN;3. 对象 new String(“1”)、/a/、{}不去重;4. 数组 [] 不去重;5.Symbol(1)不去重;
对象 key [1, '1', 0, '0', true, false, 'true', 'false', 'a', 'A', undefined, 'undefined', null, 'null', NaN, String {'1'}, Symbol(1), {}, []] 1. 去重 +0、-0、0;2. 去重 NaN;3. 去重对象 new String(“1”)、{}; 两个 /a/ 全副被删除了;4. 去重数组[];5. 去重 Symbol

下面只是简略后果的去重总结,具体的去重抉择还须要依据咱们业务场景来抉择去重办法。

演示地址

能够去 Github 仓库查看演示代码

跟着大佬学系列

次要是日常对每个进阶知识点的摸透,跟着大佬一起去深刻理解 JavaScript 的语言艺术。

后续会始终更新,心愿各位看官不要悭吝手中的赞。

❤️ 感激各位的反对!!!

❤️ 如果有谬误或者不谨严的中央,请务必给予斧正,非常感激!!!

❤️ 喜爱或者有所启发,欢送 star!!!

参考

  • 解锁多种 JavaScript 数组去重姿态
  • 数组去重的六种办法
  • 7 种办法实现数组去重
  • [JavaScript 专题之数组去重
    ](https://github.com/mqyqingfen…)

原文地址

【跟着大佬学 JavaScript】之数组去重(后果比照)

退出移动版