Ich hoffe, jemand kann mir mit diesem Javascript helfen.
Ich habe ein Objekt namens "Einstellungen" und möchte eine Funktion schreiben, die diesem Objekt neue Einstellungen hinzufügt.
Der Name und der Wert der neuen Einstellung werden als Zeichenfolgen bereitgestellt. Die Zeichenfolge mit dem Namen der Einstellung wird dann durch die Unterstriche in ein Array aufgeteilt. Die neue Einstellung sollte zum vorhandenen Objekt "Einstellungen" hinzugefügt werden, indem neue verschachtelte Objekte mit den Namen erstellt werden, die von jedem Teil des Arrays angegeben werden, mit Ausnahme des letzten Teils, der eine Zeichenfolge sein sollte, die den Wert der Einstellung angibt. Ich sollte dann in der Lage sein, mich auf die Einstellung zu beziehen und zB ihren Wert zu alarmieren. Ich kann das so statisch machen ...
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);
... der Teil, der die verschachtelten Objekte erstellt, tut dies ...
Settings["Modules"] = {};
Settings["Modules"]["Video"] = {};
Settings["Modules"]["Video"]["Plugin"] = "JWPlayer";
Da jedoch die Anzahl der Teile, aus denen der Einstellungsname besteht, variieren kann, z. B. könnte ein neuer Einstellungsname "Modules_Floorplan_Image_Src" sein, möchte ich dies dynamisch mithilfe einer Funktion wie ...
createSetting (newSettingNameArray, newSettingValue);
function createSetting(setting, value) {
// code to create new setting goes here
}
Kann mir jemand helfen, wie ich das dynamisch machen kann?
Ich nehme an, dass es dort eine for ... -Schleife geben muss, um durch das Array zu iterieren, aber ich konnte keinen Weg finden, um die verschachtelten Objekte zu erstellen.
Wenn Sie so weit gekommen sind, vielen Dank, dass Sie sich die Zeit zum Lesen genommen haben, auch wenn Sie nicht anders können.
newSettingName.split('_')
. Ich sehe keinen Sinn hinter doppelten Antworten, also da. Vielleicht erklären Sie Ihre Antwort besser.Setzen Sie eine Funktion kurz und schnell ein (keine Rekursion).
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.
Es werden bereits vorhandene Teile der Hierarchie übersprungen. Nützlich, wenn Sie nicht sicher sind, ob die Hierarchie bereits erstellt wurde.
Oder:
Eine schickere Version, bei der Sie den Wert direkt dem letzten Objekt in der Hierarchie zuweisen und Funktionsaufrufe verketten können, da das letzte Objekt zurückgegeben wird.
// 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
Hinweis: Wenn Ihre Hierarchie aus anderen Werten als Standardobjekten erstellt werden muss (dh nicht
{}
), lesen Sie auch die Antwort von TimDog weiter unten.Bearbeiten: Verwendet reguläre Schleifen anstelle von
for...in
Schleifen. Dies ist sicherer, wenn eine Bibliothek den Array-Prototyp ändert.quelle
Meine ES2015-Lösung. Behält vorhandene Werte bei.
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; };
Beispiel:
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"}}}}
quelle
Eine andere rekursive Lösung:
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; };
Anwendungsbeispiel:
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!"}}
quelle
Die Verwendung von ES6 ist verkürzt. Legen Sie Ihren Pfad in ein Array fest. Zuerst müssen Sie das Array umkehren, um das Objekt zu füllen.
let obj = ['a','b','c'] // {a:{b:{c:{}}} obj.reverse(); const nestedObject = obj.reduce((prev, current) => ( {[current]:{...prev}} ), {});
quelle
Ich liebe diese unveränderliche ES6-Methode, um einen bestimmten Wert für verschachtelte Felder festzulegen:
const setValueToField = (fields, value) => { const reducer = (acc, item, index, arr) => ({ [item]: index + 1 < arr.length ? acc : value }); return fields.reduceRight(reducer, {}); };
Verwenden Sie es dann zum Erstellen Ihres Zielobjekts.
const targetObject = setValueToField(['one', 'two', 'three'], 'nice'); console.log(targetObject); // Output: { one: { two: { three: 'nice' } } }
quelle
Hier ist eine einfache Änderung der Antwort von jlgrall, mit der für jedes Element in der verschachtelten Hierarchie unterschiedliche Werte festgelegt werden können:
var createNestedObject = function( base, names, values ) { for( var i in names ) base = base[ names[i] ] = base[ names[i] ] || (values[i] || {}); };
Ich hoffe es hilft.
quelle
Hier ist eine funktionale Lösung zum dynamischen Erstellen verschachtelter Objekte.
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); }
Beispiel:
const data = {prop: 'someData'}; const path = 'a.deep.path'; const result = nest(path, data); console.log(JSON.stringify(result)); // {"a":{"deep":{"path":{"prop":"someData"}}}}
quelle
Schätzen Sie, dass diese Frage mega alt ist! Nachdem ich jedoch festgestellt hatte, dass im Knoten so etwas getan werden muss, habe ich ein Modul erstellt und es auf npm veröffentlicht. 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
quelle
Versuchen Sie es mit der rekursiven Funktion:
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); } }
quelle
Ich denke, das ist kürzer:
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]; }
quelle
Ich fand die Antwort von @ jlgrall großartig, aber nach der Vereinfachung funktionierte sie in Chrome nicht. Hier ist mein Problem, falls jemand eine Lite-Version haben möchte:
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);
Ich hoffe das ist nützlich und relevant. Entschuldigung, ich habe gerade dieses Beispiel zerschlagen ...
quelle
Sie können Ihre eigenen Objektmethoden definieren. aus Gründen der Kürze verwende ich auch einen Unterstrich:
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; };
Beispielnutzung:
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}}
quelle
Ein Snippet für diejenigen, die verschachtelte Objekte mit Unterstützung von Array-Schlüsseln erstellen müssen, um einen Wert am Ende des Pfads festzulegen. Pfad ist die Zeichenfolge wie :
modal.product.action.review.2.write.survey.data
. Basierend auf der jlgrall-Version.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]] || {}; } } };
quelle
Verschachtelte Daten festlegen:
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"}}}
Verschachtelte Daten abrufen:
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
quelle
Eval ist wahrscheinlich übertrieben, aber das Ergebnis ist einfach zu visualisieren, ohne verschachtelte Schleifen oder Rekursionen.
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 );
Grundsätzlich schreiben Sie nach und nach eine Zeichenfolge
"obj['one']= {}", "obj['one']['two']"= {}
und bewerten sie.quelle
Versuchen Sie Folgendes: https://github.com/silkyland/object-to-formdata
var obj2fd = require('obj2fd/es5').default var fd = obj2fd({ a:1, b:[ {c: 3}, {d: 4} ] })
Ergebnis:
fd = [ a => 1, b => [ c => 3, d => 4 ] ]
quelle
Innerhalb Ihrer Schleife können Sie
lodash.set
den Pfad für Sie verwenden und erstellen:... const set = require('lodash.set'); const p = {}; const [type, lang, name] = f.split('.'); set(p, [lang, type, name], ''); console.log(p); // { lang: { 'type': { 'name': '' }}}
quelle
Hier ist eine Zerlegung in mehrere nützliche Funktionen, die jeweils vorhandene Daten beibehalten. Behandelt keine Arrays.
setDeep
: Beantwortet Frage. Zerstörungsfrei für andere Daten im Objekt.setDefaultDeep
: Gleich, aber nur gesetzt, wenn nicht bereits gesetzt.setDefault
: Legt einen Schlüssel fest, falls nicht bereits festgelegt. Gleich wie bei Pythonsetdefault
.setStructure
: Hilfsfunktion, die den Pfad erstellt.// Create a nested structure of objects along path within obj. Only overwrites the final value. let setDeep = (obj, path, value) => setStructure(obj, path.slice(0, -1))[path[path.length - 1]] = value // Create a nested structure of objects along path within obj. Does not overwrite any value. let setDefaultDeep = (obj, path, value) => setDefault(setStructure(obj, path.slice(0, -1)), path[path.length - 1], value) // Set obj[key] to value if key is not in object, and return obj[key] let setDefault = (obj, key, value) => obj[key] = key in obj ? obj[key] : value; // Create a nested structure of objects along path within obj. Does not overwrite any value. let setStructure = (obj, path) => path.reduce((obj, segment) => setDefault(obj, segment, {}), obj); // EXAMPLES let temp = {}; // returns the set value, similar to assignment console.log('temp.a.b.c.d:', setDeep(temp, ['a', 'b', 'c', 'd'], 'one')) // not destructive to 'one' setDeep(temp, ['a', 'b', 'z'], 'two') // does not overwrite, returns previously set value console.log('temp.a.b.z: ', setDefaultDeep(temp, ['a', 'b', 'z'], 'unused')) // creates new, returns current value console.log('temp["a.1"]: ', setDefault(temp, 'a.1', 'three')) // can also be used as a getter console.log("temp.x.y.z: ", setStructure(temp, ['x', 'y', 'z'])) console.log("final object:", temp)
Ich bin mir nicht sicher, warum jemand String-Pfade haben möchte:
quelle