2013-02-15 26 views
5

Dies ist eine umgekehrte Frage zu this question.Erstellen Sie ein Objekt aus der Punktnotation

ein Objekt x={a:1,b:2} und einen String c.d=3, Gegeben Objekt ändern x auf die folgenden:

{ 
    a:1, 
    b:2, 
    c:{ 
    d:3 
    } 
} 

Ich bin für eine Lösung, die nicht eval nicht verwendet. Der Anwendungsfall ist wie folgt:

x eine Objektkonfiguration zu sein, rufen wir: config.set("music.shuffle",true)

Jetzt

, music.shuffle muss irgendwie analysiert werden und zu dem internen Objekt x innerhalb der config.set Funktion, so dass x etwas wie folgt aussieht:

x={a:1,b:2,music:{shuffle:true}} 
+0

Wenn C ist eine Zeichenfolge, dann zu müssen Sie gehen, um zu versuchen, es manuell in ein Objekt zu analysieren. Ich kann fast garantieren, dass dies einfacher zu tun ist, wenn Sie die Zeichenfolge C erstellen, und Sie sollten kein manuelles Parsing durchführen müssen. Bitte zeigen Sie diesen Abschnitt des Codes, so kann ich sein – Undefined

+0

Ist die Saite garantiert weiter helfen 'dot.separated.string = value' und welche Einschränkungen auf den Wert gesetzt werden? Ist es zum Beispiel ein JSON-Typ? –

+0

Die Zeichenfolge wird als dot.se- perated garantiert, und es gibt keine Einschränkungen für den Wert. – Nemo

Antwort

10

aus der Spitze von meinem Kopf ich denke, man etwas tun kann:

function addValueToObj(obj, newProp) { 
    newProp = newProp.split("=");  // separate the "path" from the "value" 

    var path = newProp[0].split("."),  // separate each step in the "path" 
     val = newProp.slice(1).join("="); // allow for "=" in "value" 

    for (var i = 0, tmp = obj; i < path.length - 1; i++) { 
     tmp = tmp[path[i]] = {};  // loop through each part of the path adding to obj 
    } 
    tmp[path[i]] = val;    // at the end of the chain add the value in 
} 

var x = {a:1, b:2}; 
addValueToObj(x, "c.d=3"); 
// x is now {"a":1,"b":2,"c":{"d":"3"}} 
addValueToObj(x, "e.f.g.h=9=9"); 
// x is now {"a":1,"b":2,"c":{"d":"3"},"e":{"f":{"g":{"h":"9=9"}}}} 

Demo: http://jsfiddle.net/E8dMF/1/

+4

zum Fragesteller natürlich, aber ich würde empfehlen Aktualisierung, so dass Sie Eigenschaften nicht verprügeln, die bereits vorhanden sind. wenn beispielsweise x = {a: {b: 3}} und I do addValueToObj (x "A. C = 4"), dann b verschwindet. –

4

Ich glaube Dojo SetObject tut was Sie wollen. Wenn Sie (verständlicherweise) nicht das ganze Dojo reinziehen wollen, dann würde ich empfehlen, ihre (frei verfügbare) Quelle zu prüfen oder nur die Basis (nur 4k) über AMD zu laden. Es sieht etwa so aus:

function setObject(name, value, context) { 
    var parts=name.split("."), 
    p=parts.pop(); 
    for(var i=0, j; context && (j=parts[i]); i++){ 
     context = (j in context ? context[j] : context[j]={}); 
    } 
    return context && p ? (context[p]=value) : undefined; // Object 
} 

Also in Ihrem Fall, dass Sie tun würde:

x={a:1,b:2}; 
setObject("c.d", 3, x); 

Achtung: es sei denn, Sie immer nur mit trivialen Fälle behandeln, würde ich Sie bitten, noch zu gehen, um die volle Besuche Dojo-Implementierung, die sich mit Fällen beschäftigt, in denen kein Kontext bereitgestellt wird usw.

2

Hier ist eine stark kommentierte Version, die etwas einfach zu verstehen sein sollte.

// stores the configured data 
configStore = {}; 

config = { 
    set: function(keyValueString) { 

    // Split the string by the = 
    var pair = keyValueString.split('='); 

    // left of the = is the key path 
    var keyPath = pair[0]; 

    // right of the = is the value to set 
    var value = pair[1]; 

    // split keyPath into an array of keys 
    var keys = keyPath.split('.'); 
    var key; // used in loop 

    // the current level of object we are drilling into. 
    // Starts as the main root config object. 
    var currentObj = configStore; 

    // Loop through all keys in the key path, except the last one (note the -1). 
    // This creates the object structure implied by the key path. 
    // We want to do something different on the last iteration. 
    for (var i=0; i < keys.length-1; i++) { 

     // Get the current key we are looping 
     key = keys[i]; 

     // If the requested level on the current object doesn't exist, 
     // make a blank object. 
     if (typeof currentObj[key] === 'undefined') { 
     currentObj[key] = {}; 
     } 

     // Set the current object to the next level of the keypath, 
     // allowing us to drill in. 
     currentObj = currentObj[key]; 
    } 

    // Our loop doesn't handle the last key, because that's when we 
    // want to set the actual value. So find the last key in the path. 
    var lastKey = keys[keys.length-1] 

    // Set the property of the deepest object to the value. 
    currentObj[lastKey] = value; 
    } 
}; 

// Do it. 
config.set('omg.wtf.bbq=123') 

// Check it. 
alert(configStore.omg.wtf.bbq); // 123 
2

Hatte heute etwas ähnliches zu tun, hier ist eine andere Lösung. Definitiv könnte einige Aufräumarbeiten verwenden, aber es macht den Trick. Dadurch wird ein vorhandenes Objekt erweitert und keine Daten gelöscht, sofern die Eingabe gültig ist.

Es gibt keine Validierung, daher können Sie Schlüssel auf jeden Fall überschreiben, wenn Sie fehlerhafte Daten übergeben.

// @param object orig the object to extend 
// @param array keyParts the.key.path split by "." (expects an array, presplit) 
// @param mixed value the value to assign 
// @param object scoped used by the recursion, ignore or pass null 
function unflatten(orig, keyParts, value, scoped) { 
    if (!scoped) { 
     scoped = orig; 
    } 

    var nextKey = keyParts.shift(); 

    if (keyParts.length === 0) { 
     scoped[nextKey] = value; 
     return orig; 
    } 

    if (!scoped[nextKey]) { 
     scoped[nextKey] = {}; 
    } 

    scoped = scoped[nextKey]; 
    return unflatten(orig, keyParts, value, scoped); 
} 

Der Funktionsprototyp kann verbessert werden, aber dient meinen Bedürfnissen. Nennen Sie es über:

var orig = { foo: 'hello world', bar: { baz: 'goodbye world' } }; 

// lets add the key "bar.cat.aww" with value "meow" 
unflatten(orig, "bar.cat.aww".split("."), "meow"); 
/* 
    orig is { 
    foo: "hello world", 
    bar: { 
     baz: "goodbye world", 
     cat: { 
     aww: "meow" 
     } 
    } 
    } 

*/ 

// we can keep calling it to add more keys 
unflatten(orig, "some.nested.key".split("."), "weeee"); 

/* 
    orig is { 
    foo: "hello world", 
    bar: { 
     baz: "goodbye world", 
     cat: { 
     aww: "meow" 
     } 
    }, 
    some: { 
     nested: { 
     key: "weeee" 
     } 
    } 
    } 
*/ 
3

Sie können dies tun, mit lodash.set()

 
> l=require('lodash') 
> x={a:1,b:2}; 
{ a: 1, b: 2 } 
> l.set(x, 'c.d', 3) 
{ a: 1, b: 2, c: { d: 3 } } 
0

Wie wäre das?

Es erstellt oder kopiert/überschreibt ein vorhandenes Objekt.

function expando(obj, base) { 
    return Object.keys(obj) 
     .reduce((clone, key) => { 
     key.split('.').reduce((innerObj, innerKey, i, arr) => 
      innerObj[innerKey] = (i+1 === arr.length) ? obj[key] : innerObj[innerKey] || {}, clone) 
     return clone; 
    }, Object.assign({}, base)); 
} 

console.log(expando({'a.b': 1})) // { a: { b : 1 }} 
console.log(expando({'b.c': 2}, { a: 1 })) // { a: 1, b: { c: 2 }} 
console.log(expando({'b.c.d': 2, 'e.f': 3}, { a: 1 })) // { a: 1, b: { c: { d: 2 } }, e: { f: 3}} 

HINWEIS: ES6 benötigt für Pfeil Funktionen und Object.assign().

Fühlen Sie sich frei, um zu spielen:

https://jsbin.com/setazahuce/1/edit?js,console

0

Was dazu:

function setObj (str, value, obj) { 
    var ref = obj, keys = str.split('.'); 
    while (keys.length) { 
     var currentKey = keys.shift(); 
     ref[currentKey] = keys.length ? (ref[currentKey] ? ref[currentKey] : {}) : value; 
     ref = ref[currentKey]; 
    } 
} 

Beispiel mit einem Eingabeobjekt mit (könnten einige Formularwerte mit $ .serializeArray extrahiert werden)

var serializedInputs = [ 
    {name: 'fruits[1][name]', value: 'Banana'}, 
    {name: 'fruits[1][id]', value: '1'}, 
    {name: 'fruits[2][name]', value: 'Strawberry'}, 
    {name: 'fruits[2][id]', value: '2'}, 
    {name: 'fruits[3][name]', value: 'Raspberry'}, 
    {name: 'fruits[3][id]', value: '3'}, 
    {name: 'fruits[4][name]', value: 'Kiwi'}, 
    {name: 'fruits[4][id]', value: '4'}, 
    {name: 'fruits[5][name]', value: 'Mango'}, 
    {name: 'fruits[5][id]', value: '5'}, 
    {name: 'selected_fruit_id', value: '1'}, 
] 
// This variable holds the result 
var obj = {} 
serializedInputs.forEach(function(item) { 
    // Turning square brackets into dot notation 
    setObj(item.name.replace(/\]/g, '').replace(/\[/g, '.'), item.value, obj); 
}) 

Ergebnis

{ 
    "fruits": { 
     "1": { 
      "name": "Banana", 
      "id": "1" 
     }, 
     "2": { 
      "name": "Strawberry", 
      "id": "2" 
     }, 
     "3": { 
      "name": "Raspberry", 
      "id": "3" 
     }, 
     "4": { 
      "name": "Kiwi", 
      "id": "4" 
     }, 
     "5": { 
      "name": "Mango", 
      "id": "5" 
     } 
    }, 
    "selected_fruit_id": "1" 
} 
Verwandte Themen