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()
.
Любые идеи о том, как достичь этого?
Ответы
Ответ 1
Ошибка заключалась в том, что вы не можете использовать this
в grep, но вы должны использовать ссылку на элемент. Это работает:
function findPurpose(purposeName){
return $.grep(purposeObjects, function(n, i){
return n.purpose == purposeName;
});
};
findPurpose("daily");
возвращает:
[Object { purpose="daily"}]
Ответ 2
ES6
array.find((o) => { return o[propertyName] === propertyValue })
Подробнее о методе find
здесь.
ES5
var findPurpose = function(purposeName) {
for (var i = 0, len = purposeObjects.length; i < len; i++) {
if (purposeObjects[i].purpose === purposeName)
return purposeObjects[i]; // Return as soon as the object is found
}
return null; // The object was not found
}
Заметка
jQuery $.grep (или другая функция фильтрации) не является оптимальным решением.
Функция $.grep
будет перебирать все элементы массива, даже если искомый объект уже был найден во время цикла. Из документации jQuery grep:
Метод $.grep() удаляет элементы из массива по мере необходимости, чтобы все оставшиеся элементы проходили предоставленный тест. Тест - это функция, которой передается элемент массива и индекс элемента в массиве. Только если тест вернет true, элемент будет в массиве результатов.
Ответ 3
вам следует передать ссылку на элемент в функции grep:
function findPurpose(purposeName){
return $.grep(purposeObjects, function(item){
return item.purpose == purposeName;
});
};
Пример
Ответ 4
Я лично использую более общую функцию, которая работает для любого свойства любого массива:
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");
Ответ 5
Используйте функцию Underscore.js findWhere (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(...)
Ответ 6
Лучший, самый быстрый способ
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;
}
Ответ 7
Если ваш массив на самом деле представляет собой набор объектов JQuery, а просто с помощью метода . filter()?
purposeObjects.filter('[purpose="daily"]')
Ответ 8
Еще одно решение:
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; });
Эта функция не выполняется для каждого элемента из массива (она важна для больших массивов)
Ответ 9
Я создал службу util для моего приложения angular. Он имеет две функции, которые используются очень часто.
Например, у вас есть объект.
Сначала получить значение из объекта рекурсивно, не выбрасывая ошибку undefined.
{prop: {nestedProp1: {nestedProp2: somevalue}}};
получить nestedProp2 2 без undefined проверок.
Второй массив фильтров на основе
[{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');
Ответ 10
Javascript имеет функцию только для этого: Array.prototype.find. В качестве примера
function isBigEnough(element) {
return element >= 15;
}
[12, 5, 8, 130, 44].find(isBigEnough); // 130
Не сложно расширить обратный вызов функции. Однако это несовместимо с IE (и частично с Edge). Полный список рассмотрим Совместимость браузера
Ответ 11
скопировал из кода 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;
}