我想知道是否有一个已知的,内置/优雅的方法来找到一个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中有这么多函数风格的数组方法,也许已经有这样的东西了?我想很多人都必须实现这样的东西……
一种不太优雅的方法是抛出所有正确的错误消息(基于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结束过滤器来工作。
从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;
};
}
我从互联网上的多个来源获得灵感,推导出下面的解决方案。希望考虑到一些默认值,并提供一种方法来比较每个条目的通用方法,这就解决了。
用法:(给出值“秒”)
var defaultItemValue = { id: -1, name: "Undefined" };
var containers: Container[] = [{ id: 1, name: "First" }, { id: 2, name: "Second" }];
GetContainer(2).name;
实现:
class Container {
id: number;
name: string;
}
public GetContainer(containerId: number): Container {
var comparator = (item: Container): boolean => {
return item.id == containerId;
};
return this.Get<Container>(this.containers, comparator, this.defaultItemValue);
}
private Get<T>(array: T[], comparator: (item: T) => boolean, defaultValue: T): T {
var found: T = null;
array.some(function(element, index) {
if (comparator(element)) {
found = element;
return true;
}
});
if (!found) {
found = defaultValue;
}
return found;
}