objects - Javascript: cómo crear dinámicamente objetos anidados usando nombres de objetos dados por una matriz
javascript obj array (16)
¡Aprecio que esta pregunta sea mega vieja! Pero después de encontrar la necesidad de hacer algo como esto en un nodo, hice un módulo y lo publiqué en npm. Nestob
var nestob = require(''nestob'');
//Create a new nestable object - instead of the standard js object ({})
var newNested = new nestob.Nestable();
//Set nested object properties without having to create the objects first!
newNested.setNested(''biscuits.oblong.marmaduke'', ''cheese'');
newNested.setNested([''orange'', ''tartan'', ''pipedream''], { poppers: ''astray'', numbers: [123,456,789]});
console.log(newNested, newNested.orange.tartan.pipedream);
//{ biscuits: { oblong: { marmaduke: ''cheese'' } },
orange: { tartan: { pipedream: [Object] } } } { poppers: ''astray'', numbers: [ 123, 456, 789 ] }
//Get nested object properties without having to worry about whether the objects exist
//Pass in a default value to be returned if desired
console.log(newNested.getNested(''generic.yoghurt.asguard'', ''autodrome''));
//autodrome
//You can also pass in an array containing the object keys
console.log(newNested.getNested([''chosp'', ''umbridge'', ''dollar''], ''symbols''));
//symbols
//You can also use nestob to modify objects not created using nestob
var normalObj = {};
nestob.setNested(normalObj, ''running.out.of'', ''words'');
console.log(normalObj);
//{ running: { out: { of: ''words'' } } }
console.log(nestob.getNested(normalObj, ''random.things'', ''indigo''));
//indigo
console.log(nestob.getNested(normalObj, ''improbable.apricots''));
//false
Espero que alguien me pueda ayudar con este Javascript.
Tengo un Objeto llamado "Configuración" y me gustaría escribir una función que agregue nuevas configuraciones a ese objeto.
El nombre y el valor de la nueva configuración se proporcionan como cadenas. La cadena que da el nombre de la configuración se divide por los guiones bajos en una matriz. La nueva configuración debe agregarse al objeto "Configuraciones" existente creando nuevos objetos anidados con los nombres dados por cada parte de la matriz, excepto la última parte que debe ser una cadena que proporcione el valor de la configuración. Entonces debería poder referirme a la configuración y, por ejemplo, alertar sobre su valor. Puedo hacer esto de una manera estática como esta ...
var Settings = {};
var newSettingName = "Modules_Video_Plugin";
var newSettingValue = "JWPlayer";
var newSettingNameArray = newSettingName.split("_");
Settings[newSettingNameArray[0]] = {};
Settings[newSettingNameArray[0]][newSettingNameArray[1]] = {};
Settings[newSettingNameArray[0]][newSettingNameArray[1]][newSettingNameArray[2]] = newSettingValue;
alert(Settings.Modules.Mediaplayers.Video.Plugin);
... la parte que crea los objetos anidados está haciendo esto ...
Settings["Modules"] = {};
Settings["Modules"]["Video"] = {};
Settings["Modules"]["Video"]["Plugin"] = "JWPlayer";
Sin embargo, como el número de partes que componen el nombre de configuración puede variar, por ejemplo, un nuevo Nombre de configuración podría ser "Modules_Floorplan_Image_Src", me gustaría hacer esto de forma dinámica con una función como ...
createSetting (newSettingNameArray, newSettingValue);
function createSetting(setting, value) {
// code to create new setting goes here
}
¿Alguien puede ayudarme a encontrar la forma de hacer esto de forma dinámica?
Supongo que tiene que haber un ... ciclo para iterar a través de la matriz, pero no he podido encontrar la forma de crear los objetos anidados.
Si has llegado hasta aquí, muchas gracias por tomarte el tiempo de leer incluso si no puedes ayudar.
Aquí hay un simple ajuste a la respuesta de jlgrall que permite establecer valores distintos en cada elemento de la jerarquía anidada:
var createNestedObject = function( base, names, values ) {
for( var i in names ) base = base[ names[i] ] = base[ names[i] ] || (values[i] || {});
};
Espero eso ayude.
Aquí hay una solución funcional para crear dinámicamente objetos anidados.
const nest = (path, obj) => {
const reversedPath = path.split(''.'').reverse();
const iter = ([head, ...tail], obj) => {
if (!head) {
return obj;
}
const newObj = {[head]: {...obj}};
return iter(tail, newObj);
}
return iter(reversedPath, obj);
}
Ejemplo:
const data = {prop: ''someData''};
const path = ''a.deep.path'';
const result = nest(path, data);
console.log(JSON.stringify(result));
// {"a":{"deep":{"path":{"prop":"someData"}}}}
Creo que esto es más corto
Settings = {};
newSettingName = "Modules_Floorplan_Image_Src";
newSettingValue = "JWPlayer";
newSettingNameArray = newSettingName.split("_");
a = Settings;
for (var i = 0 in newSettingNameArray) {
var x = newSettingNameArray[i];
a[x] = i == newSettingNameArray.length-1 ? newSettingValue : {};
a = a[x];
}
Encontré que la respuesta de @ jlgrall fue genial, pero después de simplificarla, no funcionó en Chrome. Aquí está mi problema si alguien quiere una versión lite:
var callback = ''fn.item1.item2.callbackfunction'',
cb = callback.split(''.''),
baseObj = window;
function createNestedObject(base, items){
$.each(items, function(i, v){
base = base[v] = (base[v] || {});
});
}
callbackFunction = createNestedObject(baseObj, cb);
console.log(callbackFunction);
Espero que esto sea útil y relevante. Lo siento, acabo de romper este ejemplo ...
Eval es probablemente excesivo pero el resultado es simple de visualizar, sin bucles anidados ni recursión.
function buildDir(obj, path){
var paths = path.split(''_'');
var final = paths.pop();
for (let i = 1; i <= paths.length; i++) {
var key = "obj[''" + paths.slice(0, i).join("''][''") + "'']"
console.log(key)
eval(`${key} = {}`)
}
eval(`${key} = ''${final}''`)
return obj
}
var newSettingName = "Modules_Video_Plugin_JWPlayer";
var Settings = buildDir( {}, newSettingName );
Básicamente estás escribiendo progresivamente una cadena "obj[''one'']= {}", "obj[''one''][''two'']"= {}
y evaling it;
Me encanta esta forma inmutable de ES6 de establecer cierto valor en el campo anidado:
const setValueToField = (fields, value) => {
const reducer = (acc, item, index, arr) => ({ [item]: index + 1 < arr.length ? acc : value });
return fields.reduceRight(reducer, {});
};
Y luego úsalo para crear tu objeto objetivo.
const targetObject = setValueToField([''one'', ''two'', ''three''], ''nice'');
console.log(targetObject); // Output: { one: { two: { three: ''nice'' } } }
Mi solución ES2015. Mantiene los valores existentes.
const set = (obj, path, val) => {
const keys = path.split(''.'');
const lastKey = keys.pop();
const lastObj = keys.reduce((obj, key) =>
obj[key] = obj[key] || {},
obj);
lastObj[lastKey] = val;
};
Ejemplo:
const obj = {''a'': {''prop'': {''that'': ''exists''}}};
set(obj, ''a.very.deep.prop'', ''value'');
console.log(JSON.stringify(obj));
// {"a":{"prop":{"that":"exists"},"very":{"deep":{"prop":"value"}}}}
Otra solución recursiva:
var nest = function(obj, keys, v) {
if (keys.length === 1) {
obj[keys[0]] = v;
} else {
var key = keys.shift();
obj[key] = nest(typeof obj[key] === ''undefined'' ? {} : obj[key], keys, v);
}
return obj;
};
Ejemplo de uso:
var dog = {bark: {sound: ''bark!''}};
nest(dog, [''bark'', ''loudness''], 66);
nest(dog, [''woff'', ''sound''], ''woff!'');
console.log(dog); // {bark: {loudness: 66, sound: "bark!"}, woff: {sound: "woff!"}}
Ponga en una función, corta y rápida (sin recurrencia).
var createNestedObject = function( base, names ) {
for( var i = 0; i < names.length; i++ ) {
base = base[ names[i] ] = base[ names[i] ] || {};
}
};
// Usage:
createNestedObject( window, ["shapes", "triangle", "points"] );
// Now window.shapes.triangle.points is an empty object, ready to be used.
Salta las partes ya existentes de la jerarquía. Útil si no está seguro de si la jerarquía ya se creó.
O:
Una versión más elegante en la que puede asignar directamente el valor al último objeto en la jerarquía, y puede encadenar llamadas de función porque devuelve el último objeto.
// Function: createNestedObject( base, names[, value] )
// base: the object on which to create the hierarchy
// names: an array of strings contaning the names of the objects
// value (optional): if given, will be the last object in the hierarchy
// Returns: the last object in the hierarchy
var createNestedObject = function( base, names, value ) {
// If a value is given, remove the last name and keep it for later:
var lastName = arguments.length === 3 ? names.pop() : false;
// Walk the hierarchy, creating new objects where needed.
// If the lastName was removed, then the last object is not set yet:
for( var i = 0; i < names.length; i++ ) {
base = base[ names[i] ] = base[ names[i] ] || {};
}
// If a value was given, set it to the last name:
if( lastName ) base = base[ lastName ] = value;
// Return the last object in the hierarchy:
return base;
};
// Usages:
createNestedObject( window, ["shapes", "circle"] );
// Now window.shapes.circle is an empty object, ready to be used.
var obj = {}; // Works with any object other that window too
createNestedObject( obj, ["shapes", "rectangle", "width"], 300 );
// Now we have: obj.shapes.rectangle.width === 300
createNestedObject( obj, "shapes.rectangle.height".split(''.''), 400 );
// Now we have: obj.shapes.rectangle.height === 400
Nota: si su jerarquía necesita ser construida a partir de valores distintos a los objetos estándar (es decir, no {}
), vea también la respuesta de TimDog a continuación.
Editar: utiliza bucles regulares en lugar de for...in
bucles. Es más seguro en los casos en que una biblioteca modifica el prototipo de matriz.
Pruebe esto: https://github.com/silkyland/object-to-formdata
var obj2fd = require(''obj2fd/es5'').default
var fd = obj2fd({
a:1,
b:[
{c: 3},
{d: 4}
]
})
Resultado:
fd = [
a => 1,
b => [
c => 3,
d => 4
]
]
Puede definir sus propios métodos de Objeto; también estoy usando guion bajo para abreviar:
var _ = require(''underscore'');
// a fast get method for object, by specifying an address with depth
Object.prototype.pick = function(addr) {
if (!_.isArray(addr)) return this[addr]; // if isn''t array, just get normally
var tmpo = this;
while (i = addr.shift())
tmpo = tmpo[i];
return tmpo;
};
// a fast set method for object, put value at obj[addr]
Object.prototype.put = function(addr, val) {
if (!_.isArray(addr)) this[addr] = val; // if isn''t array, just set normally
this.pick(_.initial(addr))[_.last(addr)] = val;
};
Uso de muestra:
var obj = {
''foo'': {
''bar'': 0 }}
obj.pick(''foo''); // returns { bar: 0 }
obj.pick([''foo'',''bar'']); // returns 0
obj.put([''foo'', ''bar''], -1) // obj becomes {''foo'': {''bar'': -1}}
Un fragmento para aquellos que necesitan crear objetos anidados con soporte de claves de matriz para establecer un valor al final de la ruta. Path es la cadena como: modal.product.action.review.2.write.survey.data
. Basado en la versión jlgrall.
var updateStateQuery = function(state, path, value) {
var names = path.split(''.'');
for (var i = 0, len = names.length; i < len; i++) {
if (i == (len - 1)) {
state = state[names[i]] = state[names[i]] || value;
}
else if (parseInt(names[i+1]) >= 0) {
state = state[names[i]] = state[names[i]] || [];
}
else {
state = state[names[i]] = state[names[i]] || {};
}
}
};
intenta usar la función recursiva:
function createSetting(setting, value, index) {
if (typeof index !== ''number'') {
index = 0;
}
if (index+1 == setting.length ) {
settings[setting[index]] = value;
}
else {
settings[setting[index]] = {};
createSetting(setting, value, ++index);
}
}
Establecer datos anidados:
function setNestedData(root, path, value) {
var paths = path.split(''.'');
var last_index = paths.length - 1;
paths.forEach(function(key, index) {
if (!(key in root)) root[key] = {};
if (index==last_index) root[key] = value;
root = root[key];
});
return root;
}
var obj = {''existing'': ''value''};
setNestedData(obj, ''animal.fish.pet'', ''derp'');
setNestedData(obj, ''animal.cat.pet'', ''musubi'');
console.log(JSON.stringify(obj));
// {"existing":"value","animal":{"fish":{"pet":"derp"},"cat":{"pet":"musubi"}}}
Obtener datos anidados:
function getNestedData(obj, path) {
var index = function(obj, i) { return obj && obj[i]; };
return path.split(''.'').reduce(index, obj);
}
getNestedData(obj, ''animal.cat.pet'')
// "musubi"
getNestedData(obj, ''animal.dog.pet'')
// undefined
function assign(obj, keyPath, value) {
lastKeyIndex = keyPath.length-1;
for (var i = 0; i < lastKeyIndex; ++ i) {
key = keyPath[i];
if (!(key in obj))
obj[key] = {}
obj = obj[key];
}
obj[keyPath[lastKeyIndex]] = value;
}
Uso:
var settings = {};
assign(settings, [''Modules'', ''Video'', ''Plugin''], ''JWPlayer'');