Si bien map
es una solución adecuada para seleccionar 'columnas' de una lista de objetos, tiene un inconveniente. Si no se verifica explícitamente si las columnas existen o no, arrojará un error y (en el mejor de los casos) le proporcionará undefined
. Optaría por una reduce
solución, que simplemente puede ignorar la propiedad o incluso configurarlo con un valor predeterminado.
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;
}, []);
}
ejemplo de jsbin
Esto funcionaría incluso si uno de los elementos de la lista proporcionada no es un objeto o no contiene el campo.
Incluso puede hacerse más flexible negociando un valor predeterminado si un elemento no es un objeto o no contiene el 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;
}, []);
}
ejemplo de jsbin
Esto sería lo mismo con el mapa, ya que la longitud de la matriz devuelta sería la misma que la matriz proporcionada. (En cuyo caso a map
es un poco más 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;
}, []);
}
ejemplo de jsbin
Y luego está la solución más flexible, una que le permite cambiar entre ambos comportamientos simplemente proporcionando un 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;
}, []);
}
ejemplo de jsbin
Como los ejemplos anteriores (con suerte) arrojan algo de luz sobre cómo funciona esto, acortemos un poco la Array.concat
función utilizando la función.
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 : []));
}, []);
}
ejemplo de jsbin
var foos = objArray.pluck("foo");
.