2015-01-21 11 views
5

Ich habe eine Reihe von Objektattributen, die als strichbegrenzte Zeichenfolgen wie "availability_meta.supplier.price" kommen, und ich muss record['availability_meta']['supplier']['price'] usw. einen entsprechenden Wert zuweisen.Javascript: Konvertieren von Punkttrennzeichenfolgen in verschachtelten Objektwert

Nicht alles ist 3 Ebenen tief: viele sind nur 1 Ebene tief und viele sind tiefer als 3 Ebenen.

Gibt es eine gute Möglichkeit, dies programmgesteuert in Javascript zuzuweisen? Zum Beispiel, ich brauche:

["foo.bar.baz", 1] // --> record.foo.bar.baz = 1 
["qux.qaz", "abc"] // --> record.qux.qaz = "abc" 
["foshizzle", 200] // --> record.foshizzle = 200 

Ich stelle ich mir etwas zusammen hacken könnte, aber ich habe keinen guten Algorithmus im Auge würde so Vorschläge zu schätzen wissen. Ich benutze lodash, wenn das hilfreich ist, und offen für andere Bibliotheken, die das schnell erledigen können.

BEARBEITEN Dies ist auf dem Backend und wird selten ausgeführt, also nicht notwendig, um für Größe, Geschwindigkeit, etc. zu optimieren. In der Tat würde Code Lesbarkeit ein Pluspunkt für zukünftige Entwickler sein.

EDIT 2 Dies ist NICHT das gleiche wie das referenzierte Duplikat. Ich muss nämlich in der Lage sein, diese Zuweisung mehrere Male für das gleiche Objekt durchzuführen, und die "doppelte" Antwort überschreibt einfach die Unterschlüssel jedes Mal. Bitte wieder öffnen!

+5

1. Teilen Sie es mit '.' 2. Verwenden Sie' for'. 3. ??????? 4. PROFIT !!!! 111 – zerkms

+0

Ha ja, es ist alles über diese "???????" Abschnitt – tyler

+0

Angulars ['$ parse'] (https://docs.angularjs.org/api/ng/service/ $ parse) macht das ganz gut. Vielleicht sehen Sie sich den [Quellcode] an (https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L956) für diesen – Phil

Antwort

7

Sie erwähnten lodash in Frage, so dass ich dachte, dass ich ihr einfach Objekt set() und get() Funktionen hinzufügen sollten. Tun Sie einfach so etwas wie:

_.set(record, 'availability_meta.supplier.price', 99); 

Sie mehr darüber hier lesen: https://lodash.com/docs#set

Diese Funktionen können Sie komplexere Dinge zu tun, wie Array-Indizes angeben, etc :)

+1

yup, das ist die beste Antwort hier IMHO .. Ich habe diese .. –

+1

Einverstanden. Während zu verstehen, wie man so etwas implementiert, kann eine gute Übung in Datenstrukturen sein, nicht zu implementieren und zu verwalten, es ist ziemlich immer ein Plus. Da das OP ausdrücklich erwähnt, bereits mit lodash zu arbeiten, scheint dies die akzeptierte Antwort zu sein. – codermonkeyfuel

8

Etwas, das Sie zu erhalten begonnen:

function assignProperty(obj, path, value) { 
    var props = path.split(".") 
     , i = 0 
     , prop; 

    for(; i < props.length - 1; i++) { 
     prop = props[i]; 
     obj = obj[prop]; 
    } 

    obj[props[i]] = value; 

} 

Unter der Annahme:

var arr = ["foo.bar.baz", 1]; 

Sie es verwenden nennen würde:

assignProperty(record, arr[0], arr[1]); 

Beispiel: http://jsfiddle.net/x49g5w8L/

+0

Beachten Sie, dass Ihnen ein Parameter fehlt, wenn Sie assignProperty aufrufen. – ianaya89

+1

@ ianaya89: Danke, korrigiert. –

+0

@PastorBones: Ich habe deine Bearbeitung zurückgesetzt. Die Art, wie es geschrieben ist, ist wie vorgesehen. Das ist subtil, aber der Grund dafür ist, dass "i" nach dem Ende der Schleife gleich der letzten Eigenschaft ist (im Beispiel "baz"). Die letzte Zeile in der Funktion weist also den Wert der richtigen Eigenschaft zu. –

2

Nur tun

record['foo.bar.baz'] = 99; 

Aber wie würde das funktionieren? Es ist ausschließlich für Abenteuerlustige mit einer V8-Umgebung (Chrome oder Node Harmony) unter Verwendung von Object.observe. Wir beobachten das Objekt und erfassen das Hinzufügen neuer Eigenschaften. Wenn die "Eigenschaft" foo.bar.baz hinzugefügt wird (über eine Zuweisung), erkennen wir, dass dies eine gepunktete Eigenschaft ist, und transformieren sie in eine Zuweisung an record['foo']['bar.baz'] (Erstellen record['foo'], wenn es nicht existiert), die wiederum in eine Zuweisung umgewandelt wird record['foo']['bar']['baz']. Es geht so:

function enable_dot_assignments(changes) { 

    // Iterate over changes 
    changes.forEach(function(change) { 

     // Deconstruct change record. 
     var object = change.object; 
     var type = change.type; 
     var name = change.name; 

     // Handle only 'add' type changes 
     if (type !== 'add') return; 

     // Break the property into segments, and get first one. 
     var segments = name.split('.'); 
     var first_segment = segments.shift(); 

     // Skip non-dotted property. 
     if (!segments.length) return; 

     // If the property doesn't exist, create it as object. 
     if (!(first_segment in object)) object[first_segment] = {}; 

     var subobject = object[first_segment]; 

     // Ensure subobject also enables dot assignments. 
     Object.observe(subobject, enable_dot_assignments); 

     // Set value on subobject using remainder of dot path. 
     subobject[segments.join('.')] = object[name]; 

     // Make subobject assignments synchronous. 
     Object.deliverChangeRecords(enable_dot_assignments); 

     // We don't need the 'a.b' property on the object. 
     delete object[name]; 
    }); 
} 

Jetzt können Sie nur

tun
Object.observe(record, enable_dot_assignments); 
record['foo.bar.baz'] = 99; 

Bedenken Sie jedoch, dass eine solche Zuweisungen asynchrone sein wird, die für Sie möglicherweise nicht funktionieren. Um dies zu lösen, rufen Sie sofort nach der Zuweisung Object.deliverChangeRecords an. Oder, wenn auch nicht als syntaktisch erfreulich, könnten Sie eine Hilfsfunktion schreiben, auch die Beobachter der Einrichtung:

function dot_assignment(object, path, value) { 
    Object.observe(object, enable_dot_assignments); 
    object[path] = value; 
    Object.deliverChangeRecords(enable_dot_assignments); 
} 

dot_assignment(record, 'foo.bar.baz', 99); 
1

So etwas wie dieses Beispiel vielleicht. Es wird ein bereitgestelltes Objekt erweitern oder ein Objekt erstellen, wenn kein Objekt bereitgestellt wird.Es ist von Natur aus destruktiv, wenn Sie Schlüssel angeben, die bereits im Objekt existieren, aber Sie können das ändern, wenn das nicht das ist, was Sie wollen. Verwendet ECMA5.

/*global console */ 
 
/*members split, pop, reduce, trim, forEach, log, stringify */ 
 
(function() { 
 
    'use strict'; 
 

 
    function isObject(arg) { 
 
     return arg && typeof arg === 'object'; 
 
    } 
 

 
    function convertExtend(arr, obj) { 
 
     if (!isObject(obj)) { 
 
      obj = {}; 
 
     } 
 

 
     var str = arr[0], 
 
      last = obj, 
 
      props, 
 
      valProp; 
 

 
     if (typeof str === 'string') { 
 
      props = str.split('.'); 
 
      valProp = props.pop(); 
 
      props.reduce(function (nest, prop) { 
 
       prop = prop.trim(); 
 
       last = nest[prop]; 
 
       if (!isObject(last)) { 
 
        nest[prop] = last = {}; 
 
       } 
 

 
       return last; 
 
      }, obj); 
 

 
      last[valProp] = arr[1]; 
 
     } 
 

 
     return obj; 
 
    } 
 

 
    var x = ['fum'], 
 
     y = [ 
 
      ['foo.bar.baz', 1], 
 
      ['foo.bar.fum', new Date()], 
 
      ['qux.qaz', 'abc'], 
 
      ['foshizzle', 200] 
 
     ], 
 
     z = ['qux.qux', null], 
 
     record = convertExtend(x); 
 

 
    y.forEach(function (yi) { 
 
     convertExtend(yi, record); 
 
    }); 
 

 
    convertExtend(z, record); 
 
    document.body.textContent = JSON.stringify(record, function (key, value, Undefined) { 
 
     /*jslint unparam:true */ 
 
     /*jshint unused:false */ 
 
     if (value === Undefined) { 
 
      value = String(value); 
 
     } 
 

 
     return value; 
 
    }); 
 
}());

1

Was darüber ?

function convertDotPathToNestedObject(path, value) { 
    const [last, ...paths] = path.split('.').reverse(); 
    return paths.reduce((acc, el) => ({ [el]: acc }), { [last]: value }); 
} 

convertDotPathToNestedObject('foo.bar.x', 'FooBar') 
// { foo: { bar: { x: 'FooBar' } } } 
+0

Ich arbeite mit GraphQL, und das ist nah an der Art von Sache, die ich mit tief verschachtelten Updates arbeiten muss. Siehe: https://medium.com/pro-react/a-brief-talk-about-immutability-and-react-shelpers-70919ab8ae7c –

Verwandte Themen