Fork me on GitHub

关于fish.each()、$(selector).each()和$.each()的各自含义与区别

fish.each

  • 代码示例
    1
    2
    3
    4
    5
    fish.each(this.paymentViewSelectors, function (selector) {
    var $view = this.getView(selector);
    $view && $view.$form && $view.$form.form('clear');
    $view && $view.$grid && $view.$grid.grid('clearData');
    }.bind(this))

API介绍

  • each( obj, iterator, [context] )

    • 遍历obj,按顺序遍历输出每个值,如果存在原生的forEach方法,Underscore就使用它代替。

      1
      2
      3
      4
      fish.each([1, 2, 3], alert);
      => alerts each number in turn...
      fish.each({one: 1, two: 2, three: 3}, alert);
      => alerts each number value in turn...
    • Parameters

      • obj : Object:
        可以是数组也可以是对象

      • iterator : Function
        用来处理每个元素:
        如果obj是 数组,参数为 (element, index, obj);
        如果obj是个 对象,iterator的参数是 (value, key, obj)

      • context : Object (optional)
        如果传递了context参数,则把iterator绑定到context对象上。

fish.each的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 /**
* 数组或对象遍历
* @memberOf module:zrender/core/util
* @param {Object|Array} obj
* @param {Function} cb
* @param {*} [context]
*/
function each(obj, cb, context) {
if (!(obj && cb)) {
return;
}
if (obj.forEach && obj.forEach === nativeForEach) {
obj.forEach(cb, context);
}
else if (obj.length === +obj.length) {
for (var i = 0, len = obj.length; i < len; i++) {
cb.call(context, obj[i], i, obj);
}
}
else {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
cb.call(context, obj[key], key, obj);
}
}
}
}
  • 第一个参数obj即为需要遍历的对象,可以为数组,也可以是对象。

    • 当对象不存在时,直接返回。

    • 如果对象有原生的forEach方法,则使用原生的forEach方法代替each,依旧传入cb和context参数。

    • 关于

      1
      obj.length === +obj.length

      简单来说就是判定obj对象是否是数组。
      这段代码等价于:

      1
      if (typeof obj.length === “number” && !isNaN(obj.length))
      • ’+’号其实是将后面跟的操作数转型成了数字类型。

      • 如果obj是一个string类型,如”abc”,我们可以拿到length属性;如果是一个function,或者一个数组,我们都可以拿到他们的length属性。但如果是一个object类型的数据,它可能是不包含length属性的。

      • 因此,这个方法为了区分非数组、非字符串、非函数类型的数据,对此,我们可以尝试使用for in循环来遍历数据。同时,对于不同的数据,cb函数里的参数也不一样。

      • 可参考:http://www.css88.com/archives/5222

    • cb是来处理遍历数据的函数。

      • cb函数通过其call方法来指定函数的this指向传入的context的上下文对象。

      • call后面传入的除context以外的参数即为函数cb的入参:

        如果是数组,则为 obj[i], i, obj(对应i下标的数组元素,i下标,数组对象)。

        如果是对象,则为 obj[key], key, obj(属性key值为key时对应的value,属性key值,对象)。

    • context是上下文对象,即用来改变function的this指针的指向。

$.each

  • 代码示例:
    1
    2
    3
    4
    5
    $(function () {
    $.each([52, 97], function(index, value) {
    alert(index + ': ' + value);
    });
    })

API介绍

  • $.each( object, callback )

    • 通用例遍方法,可用于例遍对象和数组。

    • 不同于例遍 jQuery 对象的 $().each() 方法,此方法可用于例遍任何对象。

    • 回调函数拥有两个参数:第一个为对象的成员或数组的索引,第二个为对应变量或内容。如果需要退出 each 循环可使回调函数返回 false,其它返回值将被忽略。

  • 参数:

    • object:Object 需要例遍的对象或数组。

    • callback (可选):Function 每个成员/元素执行的回调函数。
      如果遍历数组,回调函数参数为(i, obj[i]) (成员索引,成员值)。
      如果遍历对象,回调函数参数为(key, obj[key]) (属性名称,属性值)。

源码

1
2
3
4
// Execute a callback for every element in the matched set.
each: function( callback ) {
return jQuery.each( this, callback );
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
each: function( obj, callback ) {
var length, i = 0;

if ( isArrayLike( obj ) ) {
length = obj.length;
for ( ; i < length; i++ ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
} else {
for ( i in obj ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
}

return obj;
},
  • $.each和fish.each的作用大体相同,都是对数组或者对象的遍历,但是其回调函数传入的参数不一样。

  • 从源码可以看出,$.each可以通过return false来中断循环。

  • 而且$.each在使用call函数时,默认传递每次遍历的对象作为回调函数的this指向,fish.each是传递context参数来指定。

$(selector).each

  • 代码示例:

    1
    2
    3
    4
    5
    $("button").click(function(){
    $("li").each(function(){
    alert($(this).text())
    });
    });
  • 大概可以看出,$(selector).each与$.each的最大不同在于它是将选择器选择的DOM元素作为遍历对象也就是obj传入的。

API介绍

  • 语法:$(selector).each(function(index,element))

  • each(callback) :以每一个匹配的元素作为上下文来执行一个函数。

  • 意味着,每次执行传递进来的函数时,函数中的this关键字都指向一个不同的DOM元素(每次都是一个不同的匹配元素)。而且,在每次执行函数时,都会给函数传递一个表示作为执行环境的元素在匹配的元素集合中所处位置的数字值作为参数(从零开始的整型)。

  • 如果想得到 jQuery对象,可以使用 $(this) 函数。
    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //this
    $("img").each(function(i){
    this.src = "test" + i + ".jpg";
    });
    //输出结果
    [ <img src="test0.jpg" />, <img src="test1.jpg" /> ]
    //$(this)
    $("li").each(function(){
    alert($(this).text())
    });
  • 返回 ‘false’ 将停止循环 (就像在普通的循环中使用 ‘break’)。返回 ‘true’ 跳至下一个循环(就像在普通的循环中使用’continue’)。

源码

  • $(selector).each与$.each的源码一致。

  • each()函数是基本上所有的框架都提供了的一个工具类函数,通过它,你可以遍历对象、数组的属性值并进行处理。

  • jQuery和jQuery对象都实现了该方法,对于jQuery对象,只是把each方法简单的进行了委托:把jQuery对象作为第一个参数传递给jQuery的each方法。

  • 换句话说:jQuery提供的each方法是对参数一(obj)提供的对象的中所有的子元素逐一进行方法调用。而jQuery对象提供的each方法则是对jQuery内部的子元素进行逐个调用。

  • 因此,与fish.each和$.each不同的是,$(selector).each明显是针对选择器所选的元素进行的each操作,而fish.each和$.each是对数组或者对象的循环遍历。

  • $(selector).each每次执行函数时,其this指向每次遍历的DOM元素;$.each则也是把传入的obj遍历时的每一个对象作为this,而fish.each可以通过context传递this。

总结

  • 关于作用:

    • fish.each与$.each一样,都是对数组或者对象的遍历;而$(selector).each则是其特殊情况:把被选择器选择的DOM元素作为对象遍历。
  • 关于参数:

    • fish:
      • 如果obj是 数组: each( obj, function(obj[i], i, obj), [context] );
      • 如果obj是 对象: each( obj, function(obj[key], key, obj), [context] )
    • $(selector).each:$(selector).each(function(index,element))
    • $.each:
      • 如果obj是 数组: each( obj, function(i, obj[i]) );
      • 如果obj是 对象: each( obj, function(key, obj[key]) )
  • 关于this:

    • fish.each可以传递context指定回调函数的this。
    • $.each默认this指向每次循环的obj成员对象;$(selector).each默认this指向每次循环的DOM对象。
  • 是否可中断:

    • $(selector).each可以通过return false结束循环;true跳过本次循环;$.each也可以通过return false结束循环。
    • fish.each里面没有涉及这一点。