jquery中循环的封装(each是如何实现的?)

我们都知道jqery中的each方法可以帮助我们遍历数组和对象

那么each中如此强大的遍历功能是是怎么实现的呢?

首先看一个简单的案例,在我们的页面中创建一些div标签、p标签和span标签,要实现对这些标签的选择并循环设置样式

<body>
    <div>div</div>
    <p>p</p> 
    <div>div</div>
    <span>span</span>
    <p>p</p> 
    <div>div</div>
</body>

 
<script>
   //将qsa方法封装起来,降低代码的错误率
    function select( selector ) {
        return document.querySelectorAll( selector ); // 得到的是一个伪数组
    }
   //封装了一个简单的each函数,目前只能遍历数组
    function each( arr, callback ) {
         for ( var i = 0; i < arr.length; i++ ) { 
            callback( arr[ i ], i );
         }
    }
    var nodes = select( 'div, p' );
    each( nodes, function ( v ) {
        v.style.border = v.nodeName == 'DIV' ? //nodeName是一个标签名的大写形式
                           '1px solid red'
                         : '1px solid blue';
    });
</script>

得到以下样式


但是在jq当中,有一个链式编程的概念,显然我们这里还没有实现,别急,我们一步一步来

要实现链式编程,最重要的是返回的是一个对象,对象中有对应的方法 比如

function function(){
   return  {
       each:function(){}
   }
}
func().each();
而我们要做的就是让select方法返回一个对象,也就是把伪数组变成一个对象

function select(selector){
   var obj = document.querySelectorAll(selector);
   obj.each = function(callback) {//使用callback处理伪数组obj中的每一个元素
       each(this,callback);//由于each是obj调用,所以this指向obj,也就是遍历obj
   } 
  return obj;
}


这样我们就实现了链式编程 如下:
select('div,p').each(function(v){
   v.style.border = '1px solid blue';
})
到这里是不是觉得已经和jq中的each方法很接近了呢 然而我们上面的代码并不是很完美 因为我们的each还不能遍历对象 还不能跳出循环,不能用this指向当前遍历元素。。。

下面我们将each方法继续完善一下

function each(arr,callback){
  for(var i=0;i<arr.length;i++) {
     // callback(arr[i],i);//此时this默认指向window 而我们想让this指向当前遍历的元素 也就是arr[i] 显然我们不能用这个
      callback.call(arr[i],arr[i],i);//我们采用方法借用将callback中的this指向arr[i]
    //jq的each方法中,采用return false跳出循环 那我们使用什么方法呢?这里就有一点绕了,我们跳出循环要用break,那问题是我们
    //要在哪里break呢 答案就是下面这句 当callback的返回值为false时,就跳出循环 
     if(callback.call(arr[i],arr[i],i)===false)break; //在这里还需注意要===而不是==,因为jq中明确告诉我们使用return false跳出循环
    //而如果我们写==的话,就证明return 0也可以跳出,我们要严格按照jq的方法去做
  }
 return arr;
}



解决了跳出循环和this指向的问题,还有一个棘手的问题,那就是如何判断对象是数组或伪数组

1>如何判断数组?

推荐使用 Object.prototype.toString.call(arr)==[object Array] ,这里不推荐使用instanceof,因为会在html嵌套(iframe)的页面中出问题

2>如何判断伪数组?

 a.必须有length属性 var length = 'length' in arr && arr.length

 b.判断他是不是数字return typeof  length==='number&&'length>=0

 c.长度需要非负

下面我们封装完整的each方法

 function isArrayLike( obj ) {
        if ( Object.prototype.toString.call( obj ) == '[object Array]' ) {
            return true;
        }
        var length = 'length' in obj && obj.length;
        return typeof length === 'number' && length >= 0;
    }

    function each( arr, callback ) {
        if ( isArrayLike ( arr ) ) {
            for ( var i = 0; i < arr.length; i++ ) {
                if ( callback.call( arr[ i ], arr[ i ], i ) === false ) break;
            }
        } else {
            for ( var k in arr ) {
                if ( callback.call( arr[ k ], arr[ k ], k ) === false ) break;
            }
        }
        return arr;
    }


至此,我们的each方法就封装完了,用于实现对数组、伪数组以及对象的遍历。


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值