浅谈JS的数组遍历方法

用过Underscore的朋友都知道,它对数组(集合)的遍历有着很是完善的API能够调用的,_.each()就是其中一个。下面就是一个简单的例子:
var arr = [1, 2, 3, 4, 5];
_.each(arr, function(el) {
    console.log(el);
});

上面的代码会依次输出1, 2, 3, 4, 5,是否是颇有意思,遍历一个数组连for循环都不用本身写了。_.each()方法遍历数组很是好用,可是它的内部实现一点都不难。下面就一块儿来看看究竟是如何实现_.each()的。在这以前,咱们先来看看_.each()的API。_.each()的通常是以下调用的:数组

_.each(arr, fn, context);

它接收3个参数,浏览器

第一个是须要遍历的数组( 实际上是对象也是能够的,这个后面咱们再一块儿来讨论);
第二个是它的回调函数(这个回调函数能够传入3个参数,如:function(el, i, arr),分别是当前元素、当前索引和原数组);
第三个是回调函数须要绑定到的上下文,即指定回调函数fn的this值。
 
好啦,需求已经很是明确了,开始干活啦!
咱们先来实现一个最简单的_.each(),它不可以修改上下文this的,接收两个参数,代码以下:
 
var _ = {}; // 假设这就是underscore哈
 
// 一个最简单的_.each方法的实现
_.each = function(arr, fn) {
  for(var i = 0; i < arr.length; i++) {
    fn(arr[i], i, arr);
  }
  return arr; // 把原数组返回
}

怎么样?是否是很简单呢?只是用一个for循环,不停的调用回调函数便可,短短几行代码就搞定了,相信没有朋友看不懂的哈!下面咱们来测试一下看能不能正常工做:app

var arr = [1, 2, 3, 4, 5];
_.each(arr, function(el, i, arr) {
  console.log(el);
});

在浏览器打开,而后控制台就会看到有正确的输出了。函数

这么简单的代码一点意思也没有,接下来看一个比较有点挑战性的例子哈。好比,数组arr有个sum属性,咱们须要把数组全部的元素求和以后存放到sum里面,以下:
var arr = [1, 2, 3, 4, 5];
arr.sum = 0; // sum属性用来存放数组元素之和
_.each(arr, function(el, i, arr) {
  this.sum += el;
});

这时候,回调函数里面用到了this,若是不绑定的话,this默认就是window,这不是咱们想要的,咱们但愿它绑定到数组arr上面。call或者apply能够实现这个功能,代码以下:测试

var _ = {}; // 假设这就是underscore哈
 
// bind,接收两个参数fn和context
// 把fn绑定到context上面
var bind = function(fn, context) {
  context = context || null;
  return function(el, i, arr) {
    fn.call(context, el, i, arr);
  }
}
 
// _.each
_.each = function(arr, fn, context) {
 
  // 调用bind方法,把fn绑定到context上面
  fn = bind(fn, context);
 
  for(var i = 0; i < arr.length; i++) {
    fn(arr[i], i, arr);
  }
  return arr;
}
 
 
// 测试用例:
var arr = [1, 2, 3, 4, 5];
arr.sum = 0; // sum属性用来存放数组元素之和
 
_.each(arr, function(el, i, arr) {
  this.sum += el;
}, arr);
 
console.log(arr.sum); // 15

好啦,这个_.each()已经足够强大了,能够正常遍历数组,还能够任意指定this值改变回调函数的上下文。可是,咱们前面有提到过,Underscore的_.each()还能够遍历对象的 ,这个实现也不难,只要判断一下传入的第一个参数是对象仍是数组,若是是数组就像咱们同样遍历,不然若是是对象,使用对象的for...in循环遍历就好了。有兴趣的能够本身试试,或者看看underscore的源码。this

注意:自从ES5标准以来,原生数组就已经具备了Array.prototype.forEach、Array.prototype.Map等遍历方法了,在项目中可使用原生的。
相关文章
相关标签/搜索