ECMA 的官网关于 push 的基本描述(链接:ECMA 数组的 push 标准),我们看下其英文的描述,如下所示
When the push method is called with zero or more arguments, the following steps are taken: 1. Let O be ? ToObject(this value). 2. Let len be ? LengthOfArrayLike(O). 3. Let argCount be the number of elements in items. 4. If len + argCount > 2^53 - 1, throw a TypeError exception. 5. For each element E of items, do a. Perform ? Set(O, ! ToString(F(len)), E, true). b. Set len to len + 1. 6. Perform ? Set(O, "length", F(len), true). 7. Return F(len).
Array.prototype.push = function (...items) {
  let O = Object(this);  // ecma 中提到的先转换为对象
  let len = this.length >>> 0;
  let argCount = items.length >>> 0;
  // 2 ^ 53 - 1 为JS能表明的最大正整数
  if (len + argCount > 2 ** 53 - 1) {
    throw new TypeError("The number of array is over the max value")
  }
  for (let i = 0; i < argCount; i++) {
    O[len + i] = items[i];
  }
  let newLength = len + argCount;
  O.length = newLength;
  return newLength;
}关键点就在于给数组本身循环添加新的元素 item,然后调整数组的长度 length 为最新的长度,即可完成 push 的底层实现
ECMA 的官网关于 pop 的基本描述(链接:ECMA 数组的 pop 标准)
When the pop method is called, the following steps are taken: 1. Let O be ? ToObject(this value). 2. Let len be ? LengthOfArrayLike(O). 3. If len = 0, then Perform ? Set(O, "length", +0F, true). Return undefined. 4. Else, Assert: len > 0. Let newLen be F(len - 1). Let index be ! ToString(newLen). Let element be ? Get(O, index). Perform ? DeletePropertyOrThrow(O, index). Perform ? Set(O, "length", newLen, true). Return element.
Array.prototype.pop = function() {
  let O = Object(this);
  let len = this.length >>> 0;
  if (len === 0) {
    O.length = 0;
    return undefined;
  }
  len--;
  let value = O[len];
  delete O[len];
  O.length = len;
  return value;
}核心思路在于删掉数组自身的最后一个元素,然后更新最新的长度,最后返回元素的值,即可达到想要的效果。另外就是在当长度为 0 的时候,如果执行 pop 操作,返回的是 undefined,需要做一下特殊处理
ECMA 的官网关于 map 的基本描述(链接:ECMA 数组的 map 标准)
When the map method is called with one or two arguments, the following steps are taken: 1. Let O be ? ToObject(this value). 2. Let len be ? LengthOfArrayLike(O). 3. If IsCallable(callbackfn) is false, throw a TypeError exception. 4. Let A be ? ArraySpeciesCreate(O, len). 5. Let k be 0. 6. Repeat, while k < len, a. Let Pk be ! ToString(F(k)). b. Let kPresent be ? HasProperty(O, Pk). c. If kPresent is true, then Let kValue be ? Get(O, Pk). Let mappedValue be ? Call(callbackfn, thisArg, « kValue, F(k), O »). Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). d. Set k to k + 1. 7. Return A.
Array.prototype.map = function(callbackFn, thisArg) {
  if (this === null || this === undefined) {
    throw new TypeError("Cannot read property  map  of null");
  }
  
  if (Object.prototype.toString.call(callbackfn) != "[object Function]") {
    throw new TypeError(callbackfn +   is not a function )
  }
  let O = Object(this);
  let T = thisArg;
  let len = O.length >>> 0;
  let A = new Array(len);
  for(let k = 0; k < len; k++) {
    if (k in O) {
      let kValue = O[k];
      // 依次传入this, 当前项,当前索引,整个数组
      let mappedValue = callbackfn.call(T, KValue, k, O);
      A[k] = mappedValue;
    }
  }
  return A;
}有了上面实现 push 和 pop 的基础思路,map 的实现也不会太难了,基本就是再多加一些判断,循环遍历实现 map 的思路,将处理过后的 mappedValue 赋给一个新定义的数组 A,最后返回这个新数组 A,并不改变原数组的值
ECMA 官网关于 reduce 的基本描述(链接:ECMA 数组的 pop 标准)
When the reduce method is called with one or two arguments, the following steps are taken: 1. Let O be ? ToObject(this value). 2. Let len be ? LengthOfArrayLike(O). 3. If IsCallable(callbackfn) is false, throw a TypeError exception. 4. If len = 0 and initialValue is not present, throw a TypeError exception. 5. Let k be 0. 6. Let accumulator be undefined. 7. If initialValue is present, then Set accumulator to initialValue. 8. Else, Let kPresent be false. Repeat, while kPresent is false and k < len, Let Pk be ! ToString(F(k)). Set kPresent to ? HasProperty(O, Pk). If kPresent is true, then Set accumulator to ? Get(O, Pk). Set k to k + 1. If kPresent is false, throw a TypeError exception. 9. Repeat, while k < len, Let Pk be ! ToString(F(k)). Let kPresent be ? HasProperty(O, Pk). If kPresent is true, then Let kValue be ? Get(O, Pk). Set accumulator to ? Call(callbackfn, undefined, « accumulator, kValue, F(k), O »). Set k to k + 1. 10. Return accumulator.
Array.prototype.reduce = function (callbackfn, initialValue) {
  // 异常处理,和 map 类似
  if (this === null || this === undefined) {
    throw new TypeError("Cannot read property  reduce  of null");
  }
  // 处理回调类型异常
  if (Object.prototype.toString.call(callbackfn) != "[object Function]") {
    throw new TypeError(callbackfn +   is not a function )
  }
  let O = Object(this);
  let len = O.length >>> 0;
  let k = 0;
  let accumulator = initialValue;  // reduce方法第二个参数作为累加器的初始值
  if (accumulator === undefined) {
    // 抛出异常是在循环完之后,异常是每个数据元素都是空
    throw new Error( Each element of the array is empty );
    // 初始值不传的处理
    for (; k < len; k++) {
      if (k in O) {
        accumulator = O[k];
        k++;
        break;
      }
    }
  }
  for (; k < len; k++) {
    if (k in O) {
      // 注意 reduce 的核心累加器
      accumulator = callbackfn.call(undefined, accumulator, O[k], O);
    }
  }
  return accumulator;
}据上面的代码及注释,有几个关键点需要重点关注:
初始值默认值不传的特殊处理;
累加器以及 callbackfn 的处理逻辑
| 数组方法 | V8 源码地址 | 
|---|---|
| pop | V8 源码 pop 的实现 | 
| push | V8 源码 push 的实现 | 
| map | V8 源码 map 的实现 | 
| slice | V8 源码 slice 的实现 | 
| filter | V8 源码 filter 的实现 |