我想知道是否有一个已知的,内置/优雅的方法来找到一个JS数组的第一个元素匹配给定的条件。c#的等效程序是List.Find。

到目前为止,我一直在使用这样的双功能组合:

// Returns the first element of an array that satisfies given predicate
Array.prototype.findFirst = function (predicateCallback) {
    if (typeof predicateCallback !== 'function') {
        return undefined;
    }

    for (var i = 0; i < arr.length; i++) {
        if (i in this && predicateCallback(this[i])) return this[i];
    }

    return undefined;
};

// Check if element is not undefined && not null
isNotNullNorUndefined = function (o) {
    return (typeof (o) !== 'undefined' && o !== null);
};

然后我可以用:

var result = someArray.findFirst(isNotNullNorUndefined);

但既然ECMAScript中有这么多函数风格的数组方法,也许已经有这样的东西了?我想很多人都必须实现这样的东西……


当前回答

现在应该清楚了,JavaScript本身并没有提供这样的解决方案;下面是最接近的两个导数,第一个最有用:

Array.prototype.some(fn)提供了在满足条件时停止的理想行为,但只返回元素是否存在;使用一些技巧并不难,比如Bergi的答案提供的解决方案。 Array.prototype.filter(fn)[0]是一个很好的单行程序,但效率最低,因为你为了得到你需要的东西而丢弃了N - 1个元素。

JavaScript中的传统搜索方法的特点是返回找到的元素的索引,而不是元素本身或-1。这避免了必须从所有可能类型的域中选择返回值;索引只能为数字,负值无效。

以上两种解决方案都不支持偏移量搜索,所以我决定这样写:

(function(ns) {
  ns.search = function(array, callback, offset) {
    var size = array.length;

    offset = offset || 0;
    if (offset >= size || offset <= -size) {
      return -1;
    } else if (offset < 0) {
      offset = size - offset;
    }

    while (offset < size) {
      if (callback(array[offset], offset, array)) {
        return offset;
      }
      ++offset;
    }
    return -1;
  };
}(this));

search([1, 2, NaN, 4], Number.isNaN); // 2
search([1, 2, 3, 4], Number.isNaN); // -1
search([1, NaN, 3, NaN], Number.isNaN, 2); // 3

其他回答

从ES 2015开始,Array.prototype.find()就提供了这个确切的功能。

对于不支持此功能的浏览器,Mozilla开发者网络提供了一个填充(粘贴在下面):

if (!Array.prototype.find) {
  Array.prototype.find = function(predicate) {
    if (this === null) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }
    var list = Object(this);
    var length = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for (var i = 0; i < length; i++) {
      value = list[i];
      if (predicate.call(thisArg, value, i, list)) {
        return value;
      }
    }
    return undefined;
  };
}

自ES6以来,数组有原生的find方法;一旦找到第一个匹配项并返回值,就停止枚举数组。

const result = someArray.find(isNotNullNorUndefined);

旧的回答:

我不得不发布一个答案来阻止这些过滤建议:-)

既然ECMAScript中有这么多函数风格的数组方法,也许已经有这样的东西了?

可以使用some Array方法迭代数组,直到满足某个条件(然后停止)。不幸的是,它只返回条件是否满足过一次,而不是由哪个元素(或在哪个索引处)满足的。所以我们要稍微修改一下:

function find(arr, test, ctx) {
    var result = null;
    arr.some(function(el, i) {
        return test.call(ctx, el, i, arr) ? ((result = el), true) : false;
    });
    return result;
}
var result = find(someArray, isNotNullNorUndefined);

一种不太优雅的方法是抛出所有正确的错误消息(基于Array.prototype.filter),但将停止对第一个结果的迭代

function findFirst(arr, test, context) {
    var Result = function (v, i) {this.value = v; this.index = i;};
    try {
        Array.prototype.filter.call(arr, function (v, i, a) {
            if (test(v, i, a)) throw new Result(v, i);
        }, context);
    } catch (e) {
        if (e instanceof Result) return e;
        throw e;
    }
}

接下来的例子是

findFirst([-2, -1, 0, 1, 2, 3], function (e) {return e > 1 && e % 2;});
// Result {value: 3, index: 5}
findFirst([0, 1, 2, 3], 0);               // bad function param
// TypeError: number is not a function
findFirst(0, function () {return true;}); // bad arr param
// undefined
findFirst([1], function (e) {return 0;}); // no match
// undefined

它通过使用throw结束过滤器来工作。

使用过滤器并从结果数组中获得第一个索引如何?

var result = someArray.filter(isNotNullNorUndefined)[0];

从ECMAScript 6开始,你可以使用Array.prototype.find。这可以在Firefox(25.0)、Chrome(45.0)、Edge(12)和Safari(7.1)中实现,但不能在Internet Explorer或其他一堆旧的或不常见的平台上实现。

例如,下面的x为106:

Const x =[100,101,102,103,104,105,106,107,108,109]。Find (function (el) { 返回el > 105; }); console.log (x);

If you want to use this right now but need support for IE or other unsupporting browsers, you can use a shim. I recommend the es6-shim. MDN also offers a shim if for some reason you don't want to put the whole es6-shim into your project. For maximum compatibility you want the es6-shim, because unlike the MDN version it detects buggy native implementations of find and overwrites them (see the comment that begins "Work around bugs in Array#find and Array#findIndex" and the lines immediately following it).