如何判断$(“..”)。each()调用是否过早中止?

时间:2013-06-12 03:22:53

标签: javascript jquery

首先,一些伪造的代码:

$("some-selector-logic").each(function() {
  if (someLogic($(this))) {
    return false;
  }
  // Otherwise do stuff related to $(this)
});

someMoreExcitingCode();

在这个例子中,我们基于一些选择器逻辑获得DOM元素的集合,然后迭代每个元素。对于我们称之为someLogic()的每个元素。如果返回true,我们将中止每个循环。否则,我们对元素执行一些逻辑,然后继续下一个元素。一旦我们完成了所有要素,我们就会继续并致电someMoreExcitingCode()

在调用someMoreExcitingCode()之前,我想知道循环是否过早中止。显然你可以做这样的事情:

var aborted = false;
$("..").each(function() {
  if (someLogic($(this))) {
    aborted = true;
    return false;
  }
});

但这对我来说感觉很草率,就像jQuery应该以另一种方式向我提供这些信息。是否有一种更为惯用的方法来实现这一点,我不知道呢?

4 个答案:

答案 0 :(得分:3)

由于jQuery函数倾向于返回相同的对象集合(允许链接),因此each()函数无法将该信息返回给您 - 它已经返回了jQuery您可以将其他方法调用链接到的对象。

根据您提供的信息,我发现使用外部标记或计数器变量来获取此信息时没有问题。如果你告诉我们更多关于为什么你需要知道的事情,我们可能会提供更多有用的建议。

答案 1 :(得分:2)

$.each()没有什么神奇之处。这是一个简单的功能,它可以满足您的需求,也可以不需要。如果没有,那么在代码示例中设置变量没有任何问题。编写自己的each()函数可以完全满足您的需求。只需几行代码即可运行循环并调用您的回调函数。

以下是jQuery 1.10.1中$.each()的源代码:

// args is for internal usage only
each: function( obj, callback, args ) {
    var value,
        i = 0,
        length = obj.length,
        isArray = isArraylike( obj );

    if ( args ) {
        if ( isArray ) {
            for ( ; i < length; i++ ) {
                value = callback.apply( obj[ i ], args );

                if ( value === false ) {
                    break;
                }
            }
        } else {
            for ( i in obj ) {
                value = callback.apply( obj[ i ], args );

                if ( value === false ) {
                    break;
                }
            }
        }

    // A special, fast, case for the most common use of each
    } else {
        if ( isArray ) {
            for ( ; i < length; i++ ) {
                value = callback.call( obj[ i ], i, obj[ i ] );

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

                if ( value === false ) {
                    break;
                }
            }
        }
    }

    return obj;
},

此代码中唯一的复杂性来自于它处理对象和数组的事实,每种情况都有两种不同的情况。

对于您正在处理的案例,可归结为:

        for ( ; i < length; i++ ) {
            value = callback.call( obj[ i ], i, obj[ i ] );

            if ( value === false ) {
                break;
            }
        }

那里没有那么多代码,如果不能做你想做的事,你可以轻松编写自己类似的迭代器,完全符合你的需要。

您甚至可以使用简单的for循环。

function doExcitingStuff() {
    var $elements = $("some-selector-logic");
    for( var i = 0;  i < $elements.length;  i++ ) {
        var $element = $($elements[i]);
        if( someLogic($element) )
            return;
        // Otherwise do stuff related to $element
    }
    someMoreExcitingCode();  // only runs if the loop completes
}

这完全取决于是什么让你的代码最干净。您可以使用$.each()或自己编写。

答案 2 :(得分:0)

可能没有您想要的那么优雅,但您可以使用Array.prototype.some

var aborted = Array.prototype.some.call($(".foo"), function(el) {
    if ($(el).hasClass('bar')) {
        return true;
    }
});

jsfiddle

答案 3 :(得分:0)

如果你真的,真的想避免使用abort布尔值,并且你不关心效率,那么你可以这样做:

$("..").removeClass('aborted').each(function() {
    if(someLogic($(this))) {
        $(this).addClass('aborted');
        return false;
    }
});

if( $("..").find('aborted').length ) {
    //each was aborted
}
else {
    //each ran to completion
}

但这有效地使用DOM来注册你的布尔状态,而不是设置一个js var。

就个人而言,我会咬紧牙关并使用你的abort = true想法。