Embora map
seja uma solução adequada para selecionar 'colunas' de uma lista de objetos, ela tem uma desvantagem. Se não for verificado explicitamente se as colunas existem ou não, ocorrerá um erro e (na melhor das hipóteses) fornecerá a você undefined
. Eu optaria por uma reduce
solução, que pode simplesmente ignorar a propriedade ou até configurá-lo com um valor padrão.
function getFields(list, field) {
// reduce the provided list to an array only containing the requested field
return list.reduce(function(carry, item) {
// check if the item is actually an object and does contain the field
if (typeof item === 'object' && field in item) {
carry.push(item[field]);
}
// return the 'carry' (which is the list of matched field values)
return carry;
}, []);
}
exemplo jsbin
Isso funcionaria mesmo se um dos itens da lista fornecida não for um objeto ou não contiver o campo.
Pode até ser mais flexível negociando um valor padrão, caso um item não seja um objeto ou não contenha o campo.
function getFields(list, field, otherwise) {
// reduce the provided list to an array containing either the requested field or the alternative value
return list.reduce(function(carry, item) {
// If item is an object and contains the field, add its value and the value of otherwise if not
carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);
// return the 'carry' (which is the list of matched field values)
return carry;
}, []);
}
exemplo jsbin
Isso seria o mesmo com o mapa, pois o comprimento da matriz retornada seria o mesmo que a matriz fornecida. (Nesse caso, a map
é um pouco mais barato que a reduce
):
function getFields(list, field, otherwise) {
// map the provided list to an array containing either the requested field or the alternative value
return list.map(function(item) {
// If item is an object and contains the field, add its value and the value of otherwise if not
return typeof item === 'object' && field in item ? item[field] : otherwise;
}, []);
}
exemplo jsbin
E há a solução mais flexível, que permite alternar entre os dois comportamentos simplesmente fornecendo um valor alternativo.
function getFields(list, field, otherwise) {
// determine once whether or not to use the 'otherwise'
var alt = typeof otherwise !== 'undefined';
// reduce the provided list to an array only containing the requested field
return list.reduce(function(carry, item) {
// If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
if (typeof item === 'object' && field in item) {
carry.push(item[field]);
}
else if (alt) {
carry.push(otherwise);
}
// return the 'carry' (which is the list of matched field values)
return carry;
}, []);
}
exemplo jsbin
Como os exemplos acima (esperançosamente) lançam alguma luz sobre o modo como isso funciona, vamos encurtar um pouco a Array.concat
função utilizando a função.
function getFields(list, field, otherwise) {
var alt = typeof otherwise !== 'undefined';
return list.reduce(function(carry, item) {
return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
}, []);
}
exemplo jsbin
var foos = objArray.pluck("foo");
.