02 Array 和 Set

106 阅读1分钟

先来看一个题目:

var arr = [
  function () {
    return 0;
  },
  function () {
    return 1;
  },
  function () {
    return 2;
  },
];
var set = new Set([
  function () {
    return 1;
  },
  function () {
    return 2;
  },
  function () {
    return 3;
  },
]);

arr.forEach((fn, i, ar) => {
  console.log(fn());
  ar.push(null);
});
set.forEach((fn, i, se) => {
  console.log(fn());
  se.add(null);
});

通过以上示例的执行结果可以知道:

  • Array 使用 forEach 方法进行遍历只遍历了最初数组的长度
  • Set 的遍历顺序是其添加的顺序
  • Set 使用 forEach 方法进行遍历则会遍历到后添加进去的值

可以推测 Array.prototype.forEach 的实现大致是:

Array.prototype.myForEach = function(cb, context) {
    // 即在首次调用 forEach 回调之前就已经确定了遍历的长度
    const length = this.length
    for (let i = 0; i < length; i++) {
        cb.apply(context, [this[i], i, this)
    }
}

同样推测 Set.prototype.forEach 的实现大致是:

Set.prototype.myForEach = function (cb, context) {
    // 推测是通过迭代器实现的
    const iterator = this[Symbol.iterator]();
    let next;
    let index = 0;
    while ((next = iterator.next()) && !next.done) {
        cb.apply(context, [next.value, index, this]);
        index++;
    }
};

其它的一些区别

  1. Set无序的,它的遍历顺序和添加顺序相同
  2. Set 中的值是唯一的,其判断基于===,对于 NaN 基于 isNaN 方法
  3. Set 查找、插入、删除值比 Array 更快
  4. Set 可以更方便得查找 NaN

SetArray 一些操作的性能测试:

const arr = [];
const set = new Set();
const n = 1000000;
for (let i = 0; i < n; i++) {
  arr.push(i);
  set.add(i);
}

// 查找
console.time("Array find");
arr.includes(131568);
console.timeEnd("Array find");

console.time("Set find");
set.has(131568);
console.timeEnd("Set find");

// 添加元素
console.time("Array push");
arr.push(n);
console.timeEnd("Array push");

console.time("Array insert");
arr.splice(23568, 0, n);
console.timeEnd("Array insert");

console.time("Set insert");
set.add(n);
console.timeEnd("Set insert");

// 删除元素
console.time("Array delete");
arr.splice(23568, 1);
console.timeEnd("Array delete");

console.time("Set delete");
set.delete(23568);
console.timeEnd("Set delete");

测试结果:
Array find: 0.122ms
Set find: 0.005ms
Array push: 0.001ms
Array insert: 1.082ms
Set insert: 0.003ms
Array delete: 0.671ms
Set delete: 0.004ms

从结果看:Set 在查找、删除和随机插入性能远好于 Array 所以在存储无序数据的场景下,应该优先选择 Set

使用场景

  1. 利用唯一性可以做数组、字符串去重
  2. 存储无序数据