Учитывая следующие три объекта, каков эффективный способ вернуть первый объект, содержащий пару ключ-значение?
var obj = {
item1: {
name: 'apple',
color: 'red'
},
item2: {
name: 'blueberry',
color: 'blue'
},
item3: {
name: 'cherry',
color: 'red'
}
};
var obj2 = {
collection: [
{
item1: {
name: 'apple',
color: 'red'
},
item2: {
name: 'blueberry',
color: 'blue'
},
item3: {
name: 'cherry',
color: 'red'
}
}
]
};
var obj3 = {
items: [
{
item1: {
name: 'apple',
color: 'red'
}
},
{
item2: {
name: 'blueberry',
color: 'blue'
},
},
{
item3: {
name: 'cherry',
color: 'red'
}
}
]
};
Я хотел бы получить те же результаты для следующих трех утверждений:
getObject(obj, 'color', 'red');
getObject(obj2, 'color', 'red');
getObject(obj3, 'color', 'red');
Выход:
{
name: 'apple',
color: 'red'
}
Вот что у меня есть до сих пор, но я думаю, что где-то отсутствует закрытие, так как оно ломается, когда функция вызывает себя:
function getObject(arg, key, val) {
if (typeof arg!=='object') return null;
switch (Object.prototype.toString.call(arg)) {
case '[object Array]':
for (var i=0; i<arg.length; ++i) {
getObject(arg[i], key, val);
}
break;
case '[object Object]':
for (var i in arg) {
if (arg.hasOwnProperty(i)) {
if (typeof arg[i]==='object') {
getObject(arg[i], key, val);
} else {
if (i===key && arg[i]===val) {
return arg;
}
}
}
}
break;
}
}
Возможный дубликат Как найти индекс объекта по ключу и значению в массиве javascript
Вы можете использовать эту функцию, которая также будет искать в более глубоко вложенных структурах данных.
function getObject(obj, prop, value) {
if (Object(obj) !== obj) return; // It is not an object
if (obj[prop] === value) return obj; // Found it
for (var key in obj) {
var result = getObject(obj[key], prop, value);
if (result) return result; // Found it
}
}
var obj = {item1: {name: 'apple',color: 'red'},item2: {name: 'blueberry',color: 'blue'},item3: {name: 'cherry',color: 'red'}};
var obj2 = {collection: [{item1: {name: 'apple',color: 'red'},item2: {name: 'blueberry',color: 'blue'},item3: {name: 'cherry',color: 'red'}}]};
var obj3 = {items: [{item1: {name: 'apple',color: 'red'}},{item2: {name: 'blueberry',color: 'blue'},},{item3: {name: 'cherry',color: 'red'}}]};
console.info(getObject(obj, 'color', 'red'));
console.info(getObject(obj2, 'color', 'red'));
console.info(getObject(obj3, 'color', 'red'));
На самом деле мне больше всего нравится ваш ответ, и в итоге я его использовал, но, к сожалению, я принял другой ответ, прежде чем увидел ваше решение. Извинения.
Без проблем. Не то чтобы вы должны это делать; но просто вы знаете: вы всегда можете пометить другой ответ как принятый, что снимет отметку с вашего предыдущего выбора. Однако, как я прокомментировал в принятом ответе: в его нынешнем виде есть ошибка.
Думаю, лучше поздно, чем никогда. Я узнал, что вы действительно можете отменить выбор принятого ответа. Еще раз спасибо за это потрясающе лаконичное решение!
Ваш подход в getObject
в порядке, однако, как общий подход, вы должны преобразовать массив для каждого из них. Вы можете использовать функцию map
, чтобы подготовить массив к процессу поиска.
Функция find
«находит» объект по заданному предикату.
Это предполагает, что индексы связаны с ключами ->
index i==0
->
items1
и так далее.
var obj = {item1: {name: 'apple',color: 'red'},item2: {name: 'blueberry',color: 'blue'},item3: {name: 'cherry',color: 'red'}};
var obj2 = {collection: [{item1: {name: 'apple',color: 'red'},item2: {name: 'blueberry',color: 'blue'},item3: {name: 'cherry',color: 'red'}}]};
var obj3 = {items: [{item1: {name: 'apple',color: 'red'}},{item2: {name: 'blueberry',color: 'blue'},},{item3: {name: 'cherry',color: 'red'}}]};
let getObject = (o, key, value) => o.find(obj => obj[key] === value);
console.info(getObject(Object.values(obj), 'color', 'red'));
console.info(getObject(obj2.collection.map((o, i) => o[`item${i+1}`]), 'color', 'red'));
console.info(getObject(obj3.items.map((o, i) => o[`item${i+1}`]), 'color', 'red'));
.as-console-wrapper { min-height: 100%; }
Спасибо за это, @Ele. Хотя я восхищаюсь краткостью решения, я не смогу использовать его прямо сейчас, потому что (1) кодовая база стандартизирована для ES5, и (2) другие разработчики, которые используют эту вспомогательную функцию, не будут знать .map()
когда это уместно. .
@thdoan нет проблем!
@thdoan, я только что наткнулся на этот комментарий: кодовая база стандартизирована на ES5. Если ES5 является требованием, то это должно быть четко указано в вопросе.
Вы можете использовать Array#some
для быстрого доступа, если объект найден.
function getObject(object, key, value) {
var result;
if (!object || typeof object !== 'object') return;
if (object[key] === value) return object;
Object.values(object).some(v => result = getObject(v, key, value));
return result;
}
var obj = { item1: { name: 'apple', color: 'red' }, item2: { name: 'blueberry', color: 'blue' }, item3: { name: 'cherry', color: 'red' } },
obj2 = { collection: [{ item1: { name: 'apple', color: 'red' }, item2: { name: 'blueberry', color: 'blue' }, item3: { name: 'cherry', color: 'red' } }] },
obj3 = { items: [{ item1: { name: 'apple', color: 'red' } }, { item2: { name: 'blueberry', color: 'blue' } }, { item3: { name: 'cherry', color: 'red' } }] };
console.info(getObject(obj, 'color', 'red'));
console.info(getObject(obj2, 'color', 'red'));
console.info(getObject(obj3, 'color', 'red'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Вы можете вызвать функцию рекурсивно, чтобы добраться до объекта, у которого нет объектов-членов, и отфильтровать его по ключу и значению:
function getObject(obj, k, v) {
for (var key in obj) {
if (typeof obj[key] === 'object') {
return getObject(obj[key], k, v);
} else if (key === k && obj[key] === v) {
return(obj);
}
}
}
var obj = {
item1: {
name: 'apple',
color: 'red'
},
item2: {
name: 'blueberry',
color: 'blue'
},
item3: {
name: 'cherry',
color: 'red'
}
};
var obj2 = {
collection: [
{
item1: {
name: 'apple',
color: 'red'
},
item2: {
name: 'blueberry',
color: 'blue'
},
item3: {
name: 'cherry',
color: 'red'
}
}
]
};
var obj3 = {
items: [
{
item1: {
name: 'apple',
color: 'red'
}
},
{
item2: {
name: 'blueberry',
color: 'blue'
},
},
{
item3: {
name: 'cherry',
color: 'red'
}
}
]
};
console.info(getObject(obj, 'color', 'red'));
console.info(getObject(obj2, 'color', 'red'));
console.info(getObject(obj3, 'color', 'red'));
К вашему сведению, вы можете использовать
Array.isArray()
, чтобы проверить, является ли объект массивом.