JQuery, как найти объект по атрибуту в массиве

Учитывая, что у меня есть массив "целевых" объектов:

//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().

Любые идеи о том, как этого добиться?


person Jesper Rønn-Jensen    schedule 07.04.2011    source источник


Ответы (11)


Нет необходимости в 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 в свой код.

person Luca Fagioli    schedule 02.04.2013
comment
Я думаю, что если (цельОбъекты[i].названиеназначения === имяназначения) следует читать, если (названиеОбъектов[i].название ===названиеназначения) - person bentwonk; 13.05.2013
comment
это лучшее и оптимальное решение!! ты рок приятель - person Partha Roy; 16.03.2016

вы должны передать ссылку на элемент в функции grep:

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

Пример

person Andrei    schedule 07.04.2011
comment
в яблочко! Это было именно то, что я в итоге сделал. - person Jesper Rønn-Jensen; 07.04.2011
comment
Функция $.grep будет перебирать все элементы массива, даже если искомый объект уже был найден во время цикла. Это не оптимально. Проверьте мой ответ. - person Luca Fagioli; 02.04.2013
comment
Полностью согласен с Лукой: $.grep() перебирает весь объект, даже если вы возвращаетесь в условном выражении! Для небольших объектов это может быть неважно, но что, если объект действительно большой, например Календарь до 2034 года? Я бы выбрал решение Луки Фаджоли как лучший ответ - person toesslab; 04.08.2013

Я лично использую более общую функцию, которая работает для любого свойства любого массива:

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");
person Johann    schedule 03.10.2013
comment
Какое-то стечение обстоятельств не позволяет этому работать в 100% случаев. У меня есть несколько методов, которые полагаются на этот метод - вызванный каким-то методом, он всегда работает, другие методы никогда не работают. Я регистрирую все звонки и не вижу видимой разницы между «работает» и «не работает». Этот вывод показывает, что третья итерация должна удовлетворять тесту и возвращать 3.true array[i][prop]: 19741 val: 19741 - person justSteve; 11.07.2017

Ошибка заключалась в том, что вы не можете использовать this в grep, но вы должны использовать ссылку на элемент. Это работает:

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

findPurpose("daily");

возвращает:

[Object { purpose="daily"}]
person Jesper Rønn-Jensen    schedule 07.04.2011
comment
Функция $.grep будет перебирать все элементы массива, даже если искомый объект уже был найден во время цикла. Это не оптимально. Проверьте мой ответ. - person Luca Fagioli; 02.04.2013
comment
Полностью согласен с Лукой: $.grep() перебирает весь объект, даже если вы возвращаетесь в условном выражении! Для небольших объектов это может быть неважно, но что, если объект действительно большой, например Календарь до 2034 года? Я бы выбрал решение Луки Фаджоли как лучший ответ - person toesslab; 04.08.2013

Используйте функцию findWhere Underscore.js (http://underscorejs.org/#findWhere):

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

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

daily будет равно:

{"purpose":"daily"}

Вот скрипка: http://jsfiddle.net/spencerw/oqbgc21x/

Чтобы вернуть более одного (если у вас их больше в массиве), вы можете использовать _.where(...)

person jbobbins    schedule 01.07.2015

Лучший, самый быстрый способ

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;
}
person Kalim    schedule 23.11.2015

Если ваш массив на самом деле представляет собой набор объектов JQuery, как насчет простого использования метода .filter()?

purposeObjects.filter('[purpose="daily"]')
person Douglas    schedule 09.04.2016

Еще одно решение:

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; });

Эта функция не выполняется для каждого элемента массива (это ценно для больших массивов).

person feeeper    schedule 09.03.2016

Я создал сервисную службу для своего углового приложения. Он имеет две функции, которые используются очень часто.

Например, у вас есть объект.

Сначала рекурсивно получаю значение из объекта без выдачи неопределенной ошибки.

{реквизит: {nestedProp1: {nestedProp2: какое-то значение}}}; получить nestedProp2 2 без неопределённых проверок.

Второй массив фильтров на основе

[{prop: {nestedProp1: {nestedProp2: somevalue1}}}, {prop: {nestedProp1: {nestedProp2: somevalue2}}}];

Найти объект из массива с вложеннымProp2=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');
person sanjay patel    schedule 07.08.2016

В JavaScript для этого есть функция: Array. прототип.найти. Как пример

function isBigEnough(element) {
  return element >= 15;
}

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

Нетрудно расширить обратный вызов функции. Однако это несовместимо с IE (и частично с Edge). Полный список см. в Браузер Совместимость

person user2688838    schedule 22.09.2017

скопирован из полифилла Array.prototype.find код Array.find и добавлен массив в качестве первого параметра.

вы можете передать поисковый запрос как функцию предиката

// Example
var listOfObjects = [{key: "1", value: "one"}, {key: "2", value: "two"}]
var result = findInArray(listOfObjects, function(element) {
  return element.key == "1";
});
console.log(result);

// the function you want
function findInArray(listOfObjects, predicate) {
      if (listOfObjects == null) {
        throw new TypeError('listOfObjects is null or not defined');
      }

      var o = Object(listOfObjects);

      var len = o.length >>> 0;

      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      var thisArg = arguments[1];

      var k = 0;

      while (k < len) {
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        k++;
      }

      return undefined;
}

person Abou-Emish    schedule 06.05.2019