数组方法手写

Array.prototype.map

Array.prototype.myMap = function (callback, thisArg) {
  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const arr = this;
  const result = new Array(arr.length);

  for (let i = 0; i < arr.length; i++) {
    // 跳过稀疏数组的空位
    if (i in arr) {
      result[i] = callback.call(thisArg, arr[i], i, arr);
    }
  }

  return result;
};

要点

  • 创建新数组,不修改原数组
  • 回调接收三个参数:元素、索引、原数组
  • 跳过稀疏数组的空位

Array.prototype.filter

Array.prototype.myFilter = function (callback, thisArg) {
  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const arr = this;
  const result = [];

  for (let i = 0; i < arr.length; i++) {
    if (i in arr) {
      if (callback.call(thisArg, arr[i], i, arr)) {
        result.push(arr[i]);
      }
    }
  }

  return result;
};

要点

  • 返回满足条件的元素组成的新数组

Array.prototype.reduce

Array.prototype.myReduce = function (callback, initialValue) {
  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const arr = this;
  let acc = initialValue;
  let startIndex = 0;

  // 没有初始值,取第一个元素作为初始值
  if (arguments.length < 2) {
    if (arr.length === 0) {
      throw new TypeError("Reduce of empty array with no initial value");
    }
    acc = arr[0];
    startIndex = 1;
  }

  for (let i = startIndex; i < arr.length; i++) {
    if (i in arr) {
      acc = callback(acc, arr[i], i, arr);
    }
  }

  return acc;
};

要点

  • 回调四个参数:累加器、当前元素、索引、原数组
  • 有初始值从索引 0 开始,无则从索引 1 开始
  • 空数组无初始值会报错

Array.prototype.flat

Array.prototype.myFlat = function (depth = 1) {
  const arr = this;

  // depth <= 0 直接返回
  if (depth <= 0) {
    return arr.slice();
  }

  // 扁平化一层
  function flattenOne(array) {
    const result = [];
    for (let i = 0; i < array.length; i++) {
      if (Array.isArray(array[i])) {
        for (let j = 0; j < array[i].length; j++) {
          result.push(array[i][j]);
        }
      } else {
        result.push(array[i]);
      }
    }
    return result;
  }

  let result = arr;
  let currentDepth = 0;

  while (currentDepth < depth) {
    // 检查是否还有数组
    const hasArray = result.some(Array.isArray);
    if (!hasArray) break;

    result = flattenOne(result);
    currentDepth++;
  }

  return result;
};

简化版(递归)

Array.prototype.myFlat = function (depth = 1) {
  const arr = this;

  function flatten(array, d) {
    if (d <= 0) return array;

    return array.reduce((acc, val) => {
      return acc.concat(Array.isArray(val) ? flatten(val, d - 1) : val);
    }, []);
  }

  return flatten(arr, depth);
};

Infinity 展平所有层级

Array.prototype.myFlat = function (depth = 1) {
  const arr = this;

  function flatten(array) {
    return array.reduce((acc, val) => {
      return acc.concat(Array.isArray(val) ? flatten(val) : val);
    }, []);
  }

  if (depth === Infinity) {
    return flatten(arr);
  }

  let result = arr;
  for (let i = 0; i < depth; i++) {
    const hasArray = result.some(Array.isArray);
    if (!hasArray) break;
    result = flatten(result);
  }

  return result;
};