Skip to content

JS 基础:数组方法实现

总结至 MDN

forEach

forEach() 方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除或者未初始化的项将被跳过。

forEach 语法

js
arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);

forEach 参数

  • callback: 为数组中每个元素执行的函数,该函数接收三个参数
  • currentValue: 数组中正在处理的当前元素
  • index(可选): 数组中正在处理的当前元素的索引
  • array(可选): forEach() 方法正在操作的数组
  • thisArg(可选): 当执行回调函数 callback 时,用作 this 的值

forEach 返回值

undefined

forEach Polyfill

js
if (!Array.prototype.forEach) {
  Array.prototype.forEach = function (callback, thisArg) {
    var T, k;

    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }

    var O = Object(this);

    var len = O.length >>> 0; //头部补零的右移运算符,表示将一个数的二进制值向右移动指定的位数.此处的目的是将任意值转化为Number,且不会出现NaN

    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }

    if (arguments.length > 1) {
      T = thisArg;
    }

    k = 0;

    while (k < len) {
      var kValue;

      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k++;
    }
  };
}

filter

filter 描述

filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。

callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。

filter 不会改变原数组,它返回过滤后的新数组。

filter 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。

filter 语法

js
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])

filter 参数

  • callback: 用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。
  • element: 数组中正在处理的当前元素
  • index(可选): 数组中正在处理的当前元素的索引
  • array(可选): 调用了 filter 的数组本身
  • thisArg(可选): 当执行回调函数 callback 时,用作 this 的值

filter 返回值

一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

filter Polyfill

js
if (!Array.prototype.filter) {
  Array.prototype.filter = function (func, thisArg) {
    'use strict';
    if (!((typeof func === 'Function' || typeof func === 'function') && this)) throw new TypeError();

    var len = this.length >>> 0,
      res = new Array(len),
      t = this,
      c = 0,
      i = -1;

    if (arguments.length > 1) {
      T = thisArg;
    }

    while (++i !== len) {
      if (i in this) {
        if (func.call(T, t[i], i, t)) {
          res[c++] = t[i];
        }
      }
    }

    res.length = c;
    return res;
  };
}

every

every 描述

every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个会使 callback 返回 falsy 的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 trueevery 就会返回 true

every 遍历的元素范围在第一次调用 callback 之前就已确定了。在调用 every 之后添加到数组中的元素不会被 callback 访问到。如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。

every 不会改变原数组。

若收到一个空数组,此方法在一切情况下都会返回 true

every 语法

js
arr.every(callback(element [, index [, array]])[, thisArg])

every 参数

  • callback: 用来测试每个元素的函数,它可以接收三个参数
  • element: 用于测试的当前值
  • index(可选): 用于测试的当前值的索引
  • array(可选): 调用 every 的当前数组
  • thisArg(可选): 当执行回调函数 callback 时,用作 this 的值

every 返回值

如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false

every Polyfill

js
if (!Array.prototype.every) {
  Array.prototype.every = function (callbackfn, thisArg) {
    'use strict';
    var T, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    var O = Object(this);

    var len = O.length >>> 0;

    if (typeof callbackfn !== 'function') {
      throw new TypeError();
    }

    if (arguments.length > 1) {
      T = thisArg;
    }

    k = 0;

    while (k < len) {
      var kValue;
      if (k in O) {
        kValue = O[k];

        var testResult = callbackfn.call(T, kValue, k, O);

        if (!testResult) {
          return false;
        }
      }
      k++;
    }
    return true;
  };
}

some

some 描述

some() 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some() 将会立即返回 true。否则,some() 返回 false

some() 被调用时不会改变数组。

some() 遍历的元素的范围在第一次调用 callback. 前就已经确定了。在调用 some() 后被添加到数组中的值不会被 callback 访问到。如果数组中存在且还未被访问到的元素被 callback 改变了,则其传递给 callback 的值是 some() 访问到它那一刻的值。已经被删除的元素不会被访问到。

some 语法

js
arr.some(callback(element[, index[, array]])[, thisArg])

some 参数

  • callback: 用来测试每个元素的函数,接受三个参数
  • element: 数组中正在处理的元素
  • index(可选): 数组中正在处理的元素的索引值
  • array(可选): some() 被调用的数组
  • thisArg(可选): 执行 callback 时使用的 this

some 返回值

数组中有至少一个元素通过回调函数的测试就会返回 true, 所有元素都没有通过回调函数的测试返回值才会为 false

some Polyfill

js
if (!Array.prototype.some) {
  Array.prototype.some = function (fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}

map

map 描述

map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。

因为 map 生成一个新数组,当你不打算使用返回的新数组却使用 map 是违背设计初衷的,请用 forEach 或者 for-of 替代。

map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)。

map 方法处理数组元素的范围是在 callback 方法第一次调用之前就已经确定了。调用 map 方法之后追加的数组元素不会被 callback 访问。如果存在的数组元素改变了,那么传给 callback 的值是 map 访问该元素时的值。

map 语法

js
var newArray = arr.map(callback(currentValue[, index[, array]])[, thisArg])

map 参数

  • callback: 生成新数组元素的函数,接受三个参数
  • currentValue: callback 数组中正在处理的当前元素
  • index(可选): callback 数组中正在处理的当前元素的索引
  • array(可选): map 方法调用的数组
  • thisArg(可选): 执行 callback 时使用的 this

map 返回值

返回一个新数组,回调函数的结果组成了新数组的每一个元素。

map Polyfill

js
if (!Array.prototype.map) {
  Array.prototype.map = function (callback, thisArg) {
    var T, A, k;

    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    var O = Object(this);

    var len = O.length >>> 0;

    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }
    if (arguments.length > 1) {
      T = arguments[1];
    }

    A = new Array(len);

    k = 0;

    while (k < len) {
      var kValue, mappedValue;
      if (k in O) {
        kValue = O[k];
        mappedValue = callback.call(T, kValue, k, O);
        A[k] = mappedValue;
      }
      k++;
    }

    return A;
  };
}

reduce

reduce 描述

reduce 为数组中的每一个元素依次执行 callback 函数,不包括数组中被删除或从未被赋值的元素。

callback 第一次执行时,如果提供了 initialValueaccumulator 取值为 initialValuecurrentValue 取数组中的第一个值,reduce 会从索引 0 的地方开始执行 callback 方法;如果没有提供 initialValue,那么 accumulator 取数组中的第一个值,currentValue 取数组中的第二个值,reduce 会从索引 1 的地方开始执行 callback 方法。

如果数组仅有一个元素(无论位置如何)并且没有提供 initialValue, 或者有提供 initialValue 但是数组为空,那么此唯一值将被返回并且 callback 不会被执行。

reduce 语法

js
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

reduce 参数

  • callback: 执行数组中每个值 (如果没有提供 initialValue 则第一个值除外)的函数,包含四个参数
  • accumulator: 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或 initialValue
  • currentValue: callback 数组中正在处理的当前元素
  • index(可选): 数组中正在处理的当前元素的索引。 如果提供了 initialValue,则起始索引号为 0,否则从索引 1 起始。
  • array(可选): 调用 reduce() 的数组
  • initialValue(可选): 作为第一次调用 callback 函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

reduce 返回值

函数累计处理的结果

reduce Polyfill

js
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function (callback, initialValue) {
      if (this === null) {
        throw new TypeError('Array.prototype.reduce ' + 'called on null or undefined');
      }
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function');
      }

      var o = Object(this);

      var len = o.length >>> 0;

      var k = 0;
      var value;

      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++;
        }
        if (k >= len) {
          throw new TypeError('Reduce of empty array ' + 'with no initial value');
        }
        value = o[k++];
      }

      while (k < len) {
        if (k in o) {
          value = callback(value, o[k], k, o);
        }
        k++;
      }
      return value;
    },
  });
}

扩展

flat

即将多维数组拍平(flatten)为一维数组。

递归

js
function wrap() {
  var ret = [];
  return function flat(a) {
    for (var item of a) {
      if (item.constructor === Array) {
        ret.concat(flat(item));
      } else {
        ret.push(item);
      }
    }
    return ret;
  };
}
console.log(wrap()(arr));

迭代

js
const flatten = function (arr) {
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
};

console.log(flatten(arr));