本文写做目的在于,对上次面试中未手写出来的map函数作一个收尾工做。其内容以map函数做为线,将其涉及到的众多知识点穿针引线梳理一下,并赋予本人学习及写做时的所感所想。既是所感所想,想必不免存在一些我的拙见,望各位大佬不吝指正,还望轻喷!!!node
还记得初识JS的map函数时webpack
[1,2,3].map((e, i, arr) => {
return 2*e; //[2,4,6]
})
复制代码
大学简单学过C语言后,第一次看到这个用法就感受特别神奇,彻底不知道它怎么运做,仅对它造成了一个大体的轮廓:你想基于原数组生成一个怎样的新数组,只要把逻辑写在回调函数里就行了。对我而言它彻底就像一个黑盒。但不觉间潜意识里却模糊了一些概念(已然与未然/主动与被动的关系)。web
以我我的入门JS的心路历程来看,假若对如下知识有所涉猎了解,就算不是十分熟练也能轻松实现map函数。知识点以下: (仅以实现map而作简单讲解,详情内容请自阅其余文献)面试
JS中基本数据类型和引用数据类型是不一样的。当咱们把一个存储基本数据类型值的变量A赋值给另外一个变量B时,本质是值传递,两个变量存储两个独立的值。但如果引用数据类型,本质是地址传递,那么此时两个变量存储的是同一个数据的地址,所以A、B会互相影响。数据库
咱们知道JS是一门多范式语言,其中就包括函数式编程。所以在JS中函数就像任何其余引用数据类型同样能够把它们存在数组里,看成函数参数传递,赋值给变量,做为对象的属性值等。编程
在JS中,当咱们用 var arr = [1,2,3] 建立一个数组并将其赋值给变量arr时,该方式本质上与var arr = new Array(1,2,3) 是没有区别的。(这里忽然意识到,还涉及到new构造函数调用的知识,优秀的你应该是知道该知识点的!!) 那么此时arr表示的数组就能够称为Array的一个实例,该实例的_proto_属性是指向构造函数Array的原型对象(也就是Array.prototype所表示的一个对象)json
关于JS函数里this的指向问题就再也不概述了,大体分为四个规则加一个特殊的箭头函数。如今对于 [1,2,3].map(callback) 咱们大概明白了,经过[1,2,3].map以原型链查询的方式找到了在Array.prototype.map里的函数,而后将callback函数做为参数传入map函数中以达到后期调用并执行相关逻辑的目的,可是咱们怎么在调用的函数中找到原数组?没错经过函数中的this。数组
学习JS时才第一次接触回调函数,一度以为本身挺懂回调,后来发现本身真的是根本不懂,还觉得本身很懂!如今让咱们看看map中回调的真容吧。promise
一直以来我都把回调函数理解成主动性,但事实上传入的回调函数是被动性的。想一下平时咱们为了实现某个功能定义了一个函数,而后传参执行该函数。但回调函数本质只是一个函数声明,之因此会执行相关的逻辑是由于以后会给该回调函数传入参数并调用该回调函数,它是被调用的。bash
那么这里又涉及到已然性和未然性。原生的map函数是被定义过的,当调用map函数实现相关逻辑时,它内部执行流程就会将数组每一个元素的(item/元素值, index/元素索引, arr/原数组)传入回调函数callback并以callback(item, index, arr)的形式调用。所以,咱们知道该回调会被传入指定的参数并调用。因此,咱们在仅须要作的声明传入的回调函数时,能够把此时回调函数的参数当作对应的数组中元素的值,在此基础上实现相关逻辑。实际上,就是把声明回调里的参数当作map执行时内部调用回调时传入的参数(item, index, arr)进行操做
其实以上两点总结来讲就是以往咱们都是先声明函数,再传参调用。而如今咱们在理解map函数时遇到的事实倒是,已经肯定了将回调函数传入map中调用时,将会在map函数内调用该回调函数,且该回调函数是被传入了固定参数的状态下调用的。所以能够说咱们已经肯定了内部会自动执行该回调,就差声明回调并传入map中执行了。因此如今对回调函数的理解是,会(hui)被调用的函数。
相信看完内容的你已经对map这个有了很清晰的认识了吧。其实我以为若是以上能掌握,那么之后绝大多数手写方法的题应该都不成问题了。那么接下来就让我贴出手写map的代码吧。(写文章真是个累人的活啊,贴出来把,写不动了!)
Array.prototype.myMap = function(callback, context) {
var arr = this;
var res = [];
context = context ? context : window;
for(let i = 0; i < arr.length; i++) {
let tem = callback.call(context, arr[i], i, arr);
res.push(tem);
}
return res;
}
复制代码
相信只要你稍微动动灵活的小脑壳确定也能实现一个reduce函数吧。
Array.prototype.myReduce = function(callback) {
var arr = this;
var res; <!--用arguments捕获第二个参数由于其值多是null,NaN之类-->
if(typeof(callback) !== "function") throw new Error("not a function");
if(arguments.length < 2 && arr.length === 0) throw new Error("empty array with no initial value");
if(arguments.length < 2 && arr.length === 1) return arr[0];
if(arguments.length > 1 && arr.length === 0) return arguments[1];
res = arguments.length > 1? arguments[1] : arr.shift();
for(let i = 0; i < arr.length; i++) {
res = callback(res, arr[i], i, arr);
}
return res;
}
复制代码
Array.prototype._myMap = function(callback, context) {
context = context ? context : window;
return this.reduce((accum, item, index, arr) =>
[...accum, callback.call(context, item, index, arr)]
, []);
}
复制代码