数组map方法探究

129 阅读2分钟

map方法

map是数组的一个方法,用来遍历数组并返回一个新的数组, 大家对map应该很熟悉,先来看看用法

image.png

map本质上可以接受两个参数,第一个参数是一个函数,这是必传的,第二个参数是第一个回调函数的this指向,这是可选的。最后返回一个新的数组

第一个参数如果不传或者不是函数,则会抛出错误

image.png

基于以上的知识点,就可以写出一个map的基本实现 因为map是数组的一个方法,所以很容易想到在Array原型上面加一个方法,并且是一个接受两个参数的函数

Array.prototype.myMap = function (fn, curThis) {

}

下一步就是方法的具体实现,首先就是考虑异常情况,就是fn不是函数的情况,可以通过判断变量的数据类型来判断,对于判断一个变量是否是函数,可以用下面的方法来做:

//下面两种方式应该都可以判断,第二种要好一点
typeof fn === "function";
Object.prototype.toString.call(fn) === "[object Function]"

就可以写出下面的代码

Array.prototype.myMap = function (fn, curThis) {
        // typeof fn === "function";
        if (Object.prototype.toString.call(fn) === "[object Function]") {
          
        }
        //如果不满足就可以使用throw来抛出一个错误,可以直接throw一个字符串,也可以使用Error构造函数来创建一个错误对象。
        throw new Error(`${fn} is not a funtion`);
      };

满足函数就可以直接进行实现了,这里实现主要就是要获取到需要遍历的那个数组,不然拿不到数组都没法做,开始本来想把数组直接通过函数传进来,但是map方法只接受两个参数,不能自己添加更多的参数,后面就想到了使用函数里的this,因为这个方法就是数组调用的,所以方法里的this指的就是要操作的数组, 拿到数组就可以对他进行操作了。(this这里是关键,确实不太好想,只能说多学多写了)

打印函数里的this:

image.png

image.png

主要实现代码

           //可以直接用this,也可以用一个变量来接受this
          const curArr = this;
           //因为map方法会返回一个数组,这里定义了一个要返回的新数组
          let resList = [];
          //遍历数组,调用传入的函数,就可以得到fn返回的值,最后把结果返回出去
          for (let i = 0; i < curArr.length; i++) {
            resList[i] = fn(curArr[i], i, curArr);
          }
          return resList;

上面实现了不用第二个参数的用法,如果要使用第二个参数,可以使用第二个参数,配合call来改变this指向

        if (Object.prototype.toString.call(fn) === "[object Function]") {
            //可以直接用this,也可以用一个变量来接受this
          const curArr = this;
           //因为map方法会返回一个数组,这里定义了一个要返回的新数组
          let resList = [];
          for (let i = 0; i < curArr.length; i++) {
              //使用call来改变fn函数的this指向
            resList[i] = fn.call(curThis, curArr[i], i, curArr);
            // resList.push(fn.call(curThis, curArr[i], i, curArr));
          }
          return resList;
        }

最终代码:

Array.prototype.myMap = function (fn, curThis) {
        // typeof fn === "function";
        if (Object.prototype.toString.call(fn) === "[object Function]") {
            //可以直接用this,也可以用一个变量来接受this
          const curArr = this;
           //因为map方法会返回一个数组,这里定义了一个要返回的新数组
          let resList = [];
          for (let i = 0; i < curArr.length; i++) {
            resList[i] = fn.call(curThis, curArr[i], i, curArr);
            // resList.push(fn.call(curThis, curArr[i], i, curArr));
          }
          return resList;
        }
        throw new Error(`${fn} is not a funtion`);
      };
      const test = [2, 9].myMap((d, i, a) => {
        console.log(d, i, a);
        console.log("ssssss", this);
        return i * d;
      });
      console.log(test);

call方法的扩展

以前只知道call方法可以改变this指向,对它的参数不太了解,下面来分析一下

在非严格模式下,如果call传入的参数是null, undefined,或者不传,那么他的this指向都将指向全局(浏览器环境中是window)

在严格模式下,call传入的参数是null,则this指向null,如果传undefined和不传参数,则this为undefined,因为严格模式下全局this就是undefined。

所以对于上面的代码,如果map方法不传第二个参数,则传入的就是undefined,所以在非严格模式的浏览器环境下就指向window,也就很好解释了结果。

同样的还有find,findIndex的第二个参数也可以指定第一个回调函数的this