map方法
map是数组的一个方法,用来遍历数组并返回一个新的数组, 大家对map应该很熟悉,先来看看用法
map本质上可以接受两个参数,第一个参数是一个函数,这是必传的,第二个参数是第一个回调函数的this指向,这是可选的。最后返回一个新的数组
第一个参数如果不传或者不是函数,则会抛出错误
基于以上的知识点,就可以写出一个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:
主要实现代码
//可以直接用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