JavaScript/jQuery中等效于LINQ Any()方法的功能

89

在JavaScript或jQuery中是否有IEnumerable.Any(Predicate<T>)的相等方法?

我正在验证一组项目,如果检测到错误,我想尽早退出。我可以使用$.each来实现,但我需要使用一个外部标志来查看项目是否实际被找到:

var found = false;
$.each(array, function(i) {
    if (notValid(array[i])) {
        found = true;
    }
    return !found;
});

有更好的方法吗?我不喜欢在JavaScript数组中使用简单的for,因为它会遍历其所有成员,而不仅仅是值。

8个回答

127

现在你可以使用 Array.prototype.some(在ES5中规范化)来达到相同的效果:

array.some(function(item) {
    return notValid(item);
});

16
简要概述:some() 方法对数组中的每个元素执行回调函数,直到找到一个使回调函数返回 true 的元素。如果找到这样的元素,some() 将立即返回 true。否则,some() 返回 false。 - Simon_Weaver
1
如果您能使用它,这就是正确的答案。它是与 Linq.Any() 等效的函数。 - Ed Bishop
如果您需要IE8兼容性,则这不是一个选项。 - Akira Yamamoto
1
更新:在 ES6 / ECMAScript 2015 中,您可以使用 myArray.some(c=>c) 来模仿 LINQ 中 .Any() 的功能。请注意,在 LINQ 中,.Any() 方法不需要委托,而 .some() 则需要。如果尝试在没有委托的情况下调用 .some(),将会导致错误,因为委托将是未定义的。 - Hardrada

19

您可以使用 jQuery 的变体 is 函数,该函数接受一个谓词:

$(array).is(function(index) {
    return notValid(this);
});

4
我认为在is函数用于数组时,应该避免使用this, 因为你将无法得到原始类型(这样使用“===”进行比较将失败)。我会使用array[i]代替。参见:http://jsfiddle.net/BYjcu/3/ - Mariano Desanze
这很有趣(我的fiddle to confirm)。但是我的直觉是要避免这种方法,因为它在一个不是jQuery选择器(本地数组)的集合上操作选择函数$.fn.is。如果有像$.is这样的实用程序函数,我会感到更安全,但这似乎是一个未记录的“功能”。 - mlhDev
据我所知,jQuery选择器是本地数组(或者至少它们使用Array.prototype),并且可能有足够的代码依赖它,以至于它永远不会改变。话虽如此,这个答案已经有将近六年的历史了。现在你应该使用本地ES5方法,或者像LoDash/Underscore等具有专门处理本地JS数组API的库。 - Xion
你说得对,我没有注意到这个答案的日期。非常抱歉(现在我无法取消我的投票!) - mlhDev

4

Xion的回答是正确的。为了扩展他的回答:

jQuery的.is(function)和.NET的IEnumerable.Any(Predicate<T>)具有相同的行为。

来自http://docs.jquery.com/is:

检查当前选择与表达式是否匹配,并在至少一个选择元素符合给定表达式时返回true。


这是打算作为评论还是编辑他们的回答?它似乎只是赞同该答案,并添加了一些上下文? - Kissaki

3

你应该使用普通的 for 循环(而不是 for ... in),这样只会循环遍历数组元素。


1
你可能想说的是“可以”。 - Simon_Weaver
@Simon_Weaver:不应该使用for in来迭代数组。 - SLaks
4
@SLaks,你误解了Simon_Weaver的评论!“你可以使用普通的for循环。”而不是“你应该...” - Chris Haines
文本中明确写着“应该”,你不能说他们被误解了,因为文字上就是这样写的。 - Kissaki

3

1

巫术。
如果无法使用array.some,可以在TypeScript中创建自己的函数:

interface selectorCallback_t<TSource> 
{
    (item: TSource): boolean;
}


function Any<TSource>(source: TSource[], predicate: selectorCallback_t<TSource> )
{
    if (source == null)
        throw new Error("ArgumentNullException: source");
    if (predicate == null)
        throw new Error("ArgumentNullException: predicate");

    for (let i = 0; i < source.length; ++i)
    {
        if (predicate(source[i]))
            return true;
    }

    return false;
} // End Function Any

这段文本的英文原意是:“转译为”,保留了HTML格式,不做解释。
function Any(source, predicate) 
 {
    if (source == null)
        throw new Error("ArgumentNullException: source");
    if (predicate == null)
        throw new Error("ArgumentNullException: predicate");
    for (var i = 0; i < source.length; ++i) 
    {
        if (predicate(source[i]))
            return true;
    }
    return false;
}

使用方法:

var names = ['Alice','Bob','Charlie','David'];
Any(names, x => x === 'Alice');

1

我建议您使用$.grep()方法。它非常接近于IEnumerable.Any(Predicate<T>)

$.grep(array, function(n, i) {
  return (n == 5);
});

这里给您提供一个可工作的示例:http://jsfiddle.net/ErickPetru/BYjcu/

2021 年更新

这个答案发布已经超过 10 年了,因此需要强调以下几点:

  1. 当时发布这个解决方案是完全合理的,因为在那个时候 JavaScript 没有原生方法来解决这个问题;
  2. 原始问题带有 jQuery 标签,因此基于 jQuery 的答案不仅是预期的,而且是必须的。因此因此而进行负面评价是没有意义的。
  3. JavaScript 世界已经发展了很多,因此如果您没有被困在 jQuery 中,请使用更更新的解决方案!这个解决方案是为了历史目的而存在,并作为旧代码的参考。

实际上,$.grep() 更像是 FindAll(Predicate<T>) - vgru
@Groo:我没有说 Any(Predicate<T>) 是最接近 grep() 的方法,只是非常接近。我同意 FindAll(Predicate<T>) 更接近它。但两者都很接近。 - Erick Petrucelli

1
我建议您尝试JavaScript的for in循环。但是,请注意,其语法与.net IEnumerable的语法非常不同。以下是一个小的示例代码。
var names = ['Alice','Bob','Charlie','David'];
for (x in names)
{
    var name = names[x];
    alert('Hello, ' + name);
}

var cards = { HoleCard: 'Ace of Spades', VisibleCard='Five of Hearts' };
for (x in cards)
{
    var position = x;
    var card = card[x];
    alert('I have a card: ' + position + ': ' + card);
}

我认为OP想要表达的是使用plain for (...) iterates over all of its members,即使用for in有时可能会产生意外结果(如果扩展了Array.prototype或者隐式调整数组大小)。 - vgru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接