WEB程序员笔记

一个前端开发工程师的个人博客

自己动手理解Array.map

了解JavaScript方法的一种方法是滚动自己的版本。今天,让我们写Array.map

事实证明,Array.map有两个参数:

  • 在数组上循环时将应用的函数
  • thisArg,将是对对象的引用,该对象将是this所提供函数中的上下文。

以我的经验,我并没有真正使用第二个参数,但是我们希望确保将其包括在内。

编写界面

由于我对扩展Array原型不感兴趣,因此我将创建一个单独的map函数。因此,我实际上将数组作为参数传递,这意味着我们将共有三个参数:

function map(arr, fn, thisArg) {
  // Magic goes here
}

将功能应用于每个元素

fn我们提供必须施加到所述阵列的每个元素。让我们做到这一点。

function map(arr, fn, thisArg) {
  const len = arr.length;
  const result = new Array(len);
  for (let i = 0; i < len; i++) {
    if (i in arr) {
      result[i] = fn(arr[i], i, arr);
    }
  }
  return result;
}

重要的是,我们将三个参数传递给fn:当前数组元素,当前数组元素的索引和原始输入数组。让我们来看一下实际情况:

const mapped = map([1, 2, 3], el => el * 2);

console.log(mapped);
// [2, 4, 6]

太好了,看起来基本操作正常!此示例不包括使用iarr传递给我们的fn,但您可以自己进行测试。

最后,thisArg

让我们不要忘记thisArg!如果thisArg提供,我们想确保我们bind提供了的功能thisArg。这是修改后的代码,以使其正常工作:

function map(arr, fn, thisArg) {
  fn = thisArg === undefined ? fn : fn.bind(thisArg);
  const len = arr.length;
  const result = new Array(len);
  for (let i = 0; i < len; i++) {
    if (i in arr) {
      result[i] = fn(arr[i], i, arr);
    }
  }
  return result;
}

在这里,它正在起作用。(请注意,由于您无法重新绑定箭头函数的this引用,因此我提供的函数不能是箭头函数。)

const obj = {
  num: 10,
};

const mapped = map(
  [1, 2, 3],
  function (el) {
    return el + this.num;
  },
  obj
);

console.log(mapped);
// [11, 12, 13]

而且我们可以看到this是指obj

奖励:通过测试驱动的开发自己编写

map使用测试驱动开发(TDD)编写了此功能!我对所有需要通过的场景进行了测试Array.map,然后一步一步地对代码进行重新设计以使它们通过。如果您尝试使用其他内置JS方法,请考虑使用此方法。

这是我用于该map功能的测试:

describe("array", () => {
  describe("map", () => {
    it("maps a simple array", () => {
      const arr = [1, 2, 3];
      const fn = el => el * 10;
      const answer = arr.map(fn);
      expect(map(arr, fn)).toEqual(answer);
    });
    it("maps an empty array", () => {
      const arr = [];
      const fn = el => el * 10;
      const answer = arr.map(fn);
      expect(map(arr, fn)).toEqual(answer);
    });
    it("maps an array with holes", () => {
      const arr = [1, 2, , , 3];
      const fn = el => el * 10;
      const answer = arr.map(fn);
      expect(map(arr, fn)).toEqual(answer);
    });
    it("uses thisArg", () => {
      const obj = {
        0: "foo",
        1: "bar",
        2: "baz"
      };
      const arr = [1, 2, 3];
      const fn = function(el, i) {
        return this[i] + el;
      };
      const answer = arr.map(fn, obj);
      expect(map(arr, fn, obj)).toEqual(answer);
    });
    it("uses the idx and arr parameters", () => {
      const arr = [1, 2, 3];
      const fn = (el, idx, arr) => JSON.stringify([el, idx, arr]);
      const answer = arr.map(fn);
      expect(map(arr, fn)).toEqual(answer);
    });
  });

希望您喜欢!让我知道您是否最终滚动了自己的其他内置方法版本。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注