Jquery如何通过属性在数组中查找对象

73

假设我有一个“purpose”对象的数组:

//array of purpose objects:
var purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

(为了简单起见,我省略了其他属性)

现在我想要一个方法,如果找到匹配的目的名称,就返回特定的对象之一。

以下方法不起作用:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(){
      return this.purpose == purposeName;
    });
};

findPurpose("daily");

但实际上它返回了一个空数组:

[]

我正在使用 JQuery 1.5.2。我也尝试过使用$.each(),但没有成功。 显然,大多数JQuery方法都是为与DOM元素一起使用而设计的(例如filter())。

有什么想法可以实现这个吗?

11个回答

96

无需 jQuery。

JavaScript 数组有一个 find 方法,所以你可以用一行代码实现:

array.find((o) => { return o[propertyName] === propertyValue })

例子


const purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

purposeObjects.find((o) => { return o["purpose"] === "weekly" })      

// output -> {purpose: "weekly"}

如果您需要兼容IE,请在代码中导入这个polyfill


1
我认为应该将 if (purposeObjects[i].purposeName === purposeName) 改为 if (purposeObjects[i].purpose === purposeName) - bentwonk
1
这是最好的和最优的解决方案!!你太棒了,伙计! - Partha Roy

40

你应该在 grep 函数中传递项的引用:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(item){
      return item.purpose == purposeName;
    });
};

示例


没错!那正是我最终做的事情。 - Jesper Rønn-Jensen
1
$.grep函数将循环遍历数组的所有元素,即使在循环期间已经找到搜索对象。这不是最优的方法。请查看我的答案。 - Luca Fagioli
2
完全同意Luca的观点:$.grep()循环遍历整个对象,即使在条件语句中返回!在较小的对象中,这可能不重要,但如果对象非常大,例如到2034年的日历,我会选择Luca Fagioli的解决方案作为最佳答案。 - toesslab

33

我个人使用一种更通用的函数,适用于任何数组的任何属性:

function lookup(array, prop, value) {
    for (var i = 0, len = array.length; i < len; i++)
        if (array[i] && array[i][prop] === value) return array[i];
}

你只需要这样调用:

lookup(purposeObjects, "purpose", "daily");

某些情况阻止了这个方法百分之百的工作。我有一些依赖这个方法的方法 - 在某些方法中被调用时它总是有效的,在其他方法中它从不有效。我正在记录所有的调用,但看不出'有效'和'无效'之间有明显的区别。这个输出表明第三次迭代应该满足测试并返回 3.true array[i][prop]: 19741 val: 19741。 - justSteve

29
错误在于你不能在grep中使用"this",而是必须使用对元素的引用。这样做可以解决问题:
function findPurpose(purposeName){
    return $.grep(purposeObjects, function(n, i){
      return n.purpose == purposeName;
    });
};

findPurpose("daily");

返回:

[Object { purpose="daily"}]

1
$.grep函数将循环遍历数组的所有元素,即使在循环期间已经找到搜索对象。这不是最优的方法。请查看我的答案。 - Luca Fagioli
2
完全同意Luca的观点:$.grep()循环遍历整个对象,即使在条件语句中返回!在较小的对象中,这可能不重要,但如果对象非常大,例如到2034年的日历,我会选择Luca Fagioli的解决方案作为最佳答案。 - toesslab

7
使用Underscore.js的findWhere函数(http://underscorejs.org/#findWhere):
var purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

var daily = _.findWhere(purposeObjects, {purpose: 'daily'});

daily将等于:

{"purpose":"daily"}

这里有一个Fiddle:http://jsfiddle.net/spencerw/oqbgc21x/ 如果你的数组中有多个元素需要返回,你可以使用_.where(...)

5

最佳、最快的方法是

function arrayLookup(array, prop, val) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].hasOwnProperty(prop) && array[i][prop] === val) {
            return array[i];
        }
    }
    return null;
}

5
如果您的数组实际上是一组 JQuery 对象,那么使用 .filter() 方法是否更简单?
purposeObjects.filter('[purpose="daily"]')

1

还有一种解决方案:

function firstOrNull(array, expr) {
  for (var i = 0; i < array.length; i++) {
    if (expr(array[i]))
      return array[i];
    }
  return null;
}

使用:firstOrNull([{ a: 1, b: 2 }, { a: 3, b: 3 }], function(item) { return item.a === 3; });

该函数不会为数组中的每个元素执行(对于大型数组很有价值)。


0
我为我的Angular应用程序创建了一个实用程序服务。它有两个经常使用的函数。
例如,您有一个对象。
首先,递归地从对象中获取值,而不会抛出未定义错误。
{prop: { nestedProp1: {nestedProp2: somevalue}}}; 获取nestedProp2 2,无需进行未定义检查。
其次,在基础上过滤数组
[{prop: { nestedProp1: {nestedProp2: somevalue1}}}, {prop: { nestedProp1: {nestedProp2: somevalue2}}}];
从数组中找到nestedProp2 = somevalue2的对象。
app.service('UtilService', function(httpService) {
this.mapStringKeyVal = function(map, field) {
    var lastIdentifiedVal = null;
    var parentVal = map;
    field.split('.').forEach(function(val){
        if(parentVal[val]){
            lastIdentifiedVal = parentVal[val]; 
            parentVal = parentVal[val]; 
        }
    });
    return lastIdentifiedVal;
}


this.arrayPropFilter = function(array, field,value) {
    var lastIdentifiedVal = null;
    var mapStringKeyVal = this.mapStringKeyVal;
    array.forEach(function(arrayItem){
        var valueFound = mapStringKeyVal(arrayItem,field);
        if(!lastIdentifiedVal  && valueFound && valueFound==value){
            lastIdentifiedVal = arrayItem;
        }
    });
    return lastIdentifiedVal;
}});

对于当前问题的解决方案,请注入UtilService并调用:

UtilService.arrayPropFilter(purposeArray,'purpose','daily');

或者更高级

UtilService.arrayPropFilter(purposeArray,'purpose.nestedProp1.nestedProp2','daily');

0
JavaScript有一个专门的函数:Array.prototype.find。例如:
function isBigEnough(element) {
  return element >= 15;
}

[12, 5, 8, 130, 44].find(isBigEnough); // 130

将回调扩展为函数并不困难。但是这与IE(部分与Edge)不兼容。有关完整列表,请查看浏览器兼容性


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