在平常 Coding 中,码农们确定少不了对数组的操做,其中很经常使用的一个操做就是对数组进行遍历,查看数组中的元素,而后一顿操做猛如虎。数组
就好像咱们去买水果,在一堆水果中,一个一个看好坏。这个好,嗯,要,放入袋中;这个很差,不要,放回;这个好,嗯,呀 …浏览器
在我认识的众多计算机语言中,如 Java、Python、JS,都有对 forEach 的实现,今天暂且简单地说说在 JavaScript 中 forEach。函数
学习或研究语言提供的函数 API,通常都会有这么几步:学习
代码很重要,但思惟、认知更重要!this
那么,很少说,先来看看 forEach 函数的原型:prototype
/** * currentValue : 遍历到的当前元素 * index : 当前元素的索引值 (可选) * arr : 当前元素所属的数组对象,即 array (可选) * thisValue : 当执行回调函数时用做 this 的值(参考对象) (可选) * * 返回值: undefined */ 1. array.forEach(function(currentValue, index, arr), thisArg); 2. arr.forEach(callback[, thisArg]);
这里有两种函数原型的表达方式,第一种看起来稍微清楚明白点,第二种偏高大上,Linux 上很常见。看我的所接触的语言及习惯,哪一种适合本身,哪一种能让本身更容易理解、明白就看哪一种就好,没必要纠结!code
适合本身的才是最好的!对象
其中 currentValue 就是遍历到的当前元素,拿买苹果做例子,咱们从一堆苹果中,一个个挑,而 currentValue 就是咱们从水果堆中拿到的那个苹果;索引
index 是当前元素的索引,也就是咱们手中的苹果是拿过的苹果中是第几个,好比这个是拿的我第二个,那 index 就是 1。为何是 1 不是 2 呢 ?由于计算机语言是从 0 开始的,这是一个哲学问题;接口
arr 是当前元素所属的数组对象,说白了就是那一堆苹果。
而 thisArg,就很难解释了。仍是看例子吧,说千遍,不如作一步,本身敲一下,运行后,理解可能更深。
后面三个参数都是可选的,无关紧要,估计他们很想哭。
来个栗子:
var array1 = ['a', 'b', 'c']; var array2 = ['1','2','3']; array1.forEach(function(currentValue, index, arr) { console.log(currentValue, index, arr, this); },array2); # 输出 // 若是给 forEach() 传递了 thisArg 参数,当调用时,它将被传给 callback 函数,做为它的 this 值。不然,将会传入 undefined 做为它的 this 值 > "a" 0 ["a", "b", "c"] ["1", "2", "3"] > "b" 1 ["a", "b", "c"] ["1", "2", "3"] > "c" 2 ["a", "b", "c"] ["1", "2", "3"]
咱们看到,数组的每个元素及他们对应的索引被依次输入,而 arr 就是它本身,而 this 则是 array2,是咱们在调用 forEach 时传进去的,在里面被看成 this 了。
源码呢 ?
说到这,JavaScript 不像 Java 同样,它提供的函数的源码并非用自己本身这种语言编写的,而是用 C 或 C++ 写的。这些函数,其实只是一种对外公开的规范,就像是向开发提供的接口同样。因此严格讲,JavaScript 不是一门语言,而是一套规范,一套 API。
这与不少语言有着很大的不一样。
对同一个函数,或者说同一个 API,也有多种不一样的方式实现,所以,咱们很难像 Java 同样查看 forEach 的源码,一个函数,在同一个版本,源码一致。
咱们只能经过一些公开的参考一些浏览器内核公开代码。
例如,mozilla 的 forEach 源码:
/* ES5 15.4.4.18. */ function ArrayForEach(callbackfn/*, thisArg*/) { var O = ToObject(this); var len = ToLength(O.length); if (arguments.length === 0) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.forEach"); if (!IsCallable(callbackfn)) ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); var T = arguments.length > 1 ? arguments[1] : void 0; for (var k = 0; k < len; k++) { if (k in O) { callContentFunction(callbackfn, T, O[k], k, O); } } return void 0; }
那咱们能不能根据实际用途效果,参照前面的源码,本身用 JavaScript 手写一个 forEach 呢 ?
固然,能够!
我这里写了两种不一样的 forEach 的实现,若是你有更好的方式,欢迎贴代码交流。
1.使用 call 方式
Array.prototype.forEach = function(callback,thisArg){ var len = this.length; for(var i = 0; i < len; i++){ // callback(this[i], i, this); callback.call(thisArg,this[i], i, this); } }
2.使用 bind 方式
Array.prototype.forEach = function(callback,thisArg){ var len = this.length; callback = callback.bind(thisArg); for(var i = 0; i < len; i++){ callback(this[i], i, this); } }
固然,代码只给了关键性代码,里面少了不少合理性判断,特殊处理等。但思路就在那了,更完善的代码待你们来补充,一块儿交流。
原创不简单,码字不易,点个赞,行不行 !