前端的朋友应该都用过一些迭代器,比如jQuery中的$.each()或underscore中的_.each();今天我们就来自己实现一个简单的迭代器:
我们仿照一些JS库的接口风格:each(arrOrObj, function(){})
1 var each = function(obj, fn){ 2 var len = obj.length,i = 0; 3 if( typeof(len) == 'undefined' ){ 4 //如果是对象 ,对象没有length属性 5 for( i in obj ){ 6 if(false === fn.call(obj[i], obj[i], i)){break;} 7 } 8 } 9 else{ 10 //如果是数组 11 for(; i<len; i++){ 12 if ( false === fn.call(obj[i],i+1,obj[i]) ){ 13 break; 14 } 15 } 16 } 17 };
我们来分析一下,首先我们要判断需要迭代的是对象还是数组,是对象,就遍历每一个属性,是数组就遍历每一个数组的值。
数组和对象的区别在于数组有长度,对象没有长度。我们可以通过这一点来判断。
接下来是分别处理这两种情况:如果是对象,就要遍历每一个属性,我们打开调试器做一个小实验:
1 var obj = {'a':1,'b':2,'c':3} 2 3 for(i in obj){console.log('i: ',i,' v: ', obj[i]);} 4 i: a v: 1 5 i: b v: 2 6 i: c v: 3
看来我们可以用for来遍历对象,接下来就是将遍历出来的结果传递到迭代器的回调函数中。
为了确保上下文关系,我们用call的方法调用回调函数,fn.call(obj[i], obj[i], i);
那么如果是数组呢:我们已经有了长度,就直接遍历;此时问题来了,原生的for循环中我们可以利用continue和break来控制循环,现在有该怎么实现呢?
我们可以利用回调函数的返回值来实现同样的效果:true、false。
这样我们就简单的实现了一个迭代器,考虑到实际项目中,我们还是使用一些比较成熟的js库,原因是这些js库的迭代器比较稳定,而且还提供了丰富的功能:
比如underscore