2016-04-02 15 views
3

Kürzlich habe ich festgestellt, dass ich ein Objekt aus Attributen in einem HTML-Tag erstellen musste. Ich dies in einer AngularJS Umgebung tue, so hyphenated Attribute camelcase umgewandelt werden, aber ich konnte auch das gleiche tun data- Attributen und datasetObjekt durch Gruppieren von CamelCase-Eigenschaften erstellen

So zum Beispiel habe ich:

<element person-name="Grant" animation-jump="123" /> 

, die das Objekt gibt

{ 
    "personName" : "Grant", 
    "animationJump" : "123" 
{ 

Mein Problem ist, dass ich dann das Objekt Camelcase in ein strukturiertes Objekt konvertieren möchten:

Ich habe eine JSFiddle meiner Quint Einheit erstellt Test-https://jsfiddle.net/gdt3bonw/ Es ist eigentlich für den Fall arbeitet Ich möchte das nur 1 Ebene ist, aber ich mag es für eine beliebige Anzahl von Ebenen arbeiten, weil ich, dass es vorhersehen werden benötigt werden und so kann ich den Code öffentlich veröffentlichen.

+1

Sie sollten sich [Schnellste Möglichkeit, verschachtelte JSON-Objekte zu glätten/zu entlasten] (http://stackoverflow.com/q/19098797) ansehen/1048572) – Bergi

Antwort

2

Wir werden die Schlüssel des Objekts durchlaufen reduce, Aufbau des Ergebnisses. Wir zerlegen jeden Schlüssel in seine Komponenten, wie personName in person und name. Wir durchlaufen diese Komponenten und erstellen Unterobjekte, wenn sie nicht bereits existieren. Schließlich fügen wir dem innersten Unterobjekt die letzte Komponente als Eigenschaft mit dem betreffenden Wert hinzu.

Object.keys(input).reduce((result, key) => { 
    var parts = key.match(/(^|[A-Z])[a-z]+/g) . map(part => part.toLowerCase()); 
    var leaf = parts.pop(); 
    var obj = result; 

    parts.forEach(part => obj = obj[part] = obj[part] || {}); 
    obj[leaf] = input[key]; 

    return result; 
}, {}); 
+0

Habe das ECMA-Bit entfernt - Denkst du, du könntest mein JSFiddle bearbeiten? –

+0

JSFiddle aktualisiert haben https://jsfiddle.net/gdt3bonw/1/ –

+0

Sie sollten mit 'deepEqual' testen. –

0

Dies ist nicht die beste Lösung, aber man kann tatsächlich Arrays als Schlüssel verwendet, in dieser besonderen Situation, indem man sich in einen String konvertieren:

obj[["animation","Jump"].join()] = "123"; 

Dies wird mit Ihrem ursprünglichen Objekt arbeitet.

1

Sie können das nicht auf diese Weise verwenden, und ich denke nicht, dass es ein logischer Vorschlag wäre. Unten erkläre ich, warum es nicht ging.

obj[["animation","jump"]] = "123" 

ersetzen Sie es mit

obj["animation"]["jump"] = "123" 

und es ist alles in Ordnung.

Warum unterstütze ich Ihre Idee nicht?

  • Es ist unordentlich zu verwenden, es gibt keinen Stil dabei.
  • Es gibt keine Logik bei der Verwendung eines Arrays als Objektschlüssel
  • Es gibt eine andere Möglichkeit, ein Objekt mit dem Schlüssel aufzurufen: mit einem Punkt, und das wird Ihre Idee nicht unterstützen. Ich denke jeder kann sich vorstellen warum.
0

Eine Lösung, die Regex to split camel case Zeichenfolge verwendet.

var obj = { "animationsJump": "123", "animationsRun": "456", "animationsHide": "789", "personName": "Grant", "personPetsDog": "Snowy", "personPetsCat": "Snowball" }, 
 
    newObject = {}; 
 

 
Object.keys(obj).forEach(function (k) { 
 
    var path = k.split(/(?=[A-Z])/).map(function (s) { 
 
      return s.toLowerCase(); 
 
     }), 
 
     last = path.pop(); 
 
    path.reduce(function (r, a) { 
 
     r[a] = r[a] || {}; 
 
     return r[a]; 
 
    }, newObject)[last] = obj[k]; 
 
}); 
 

 
document.write('<pre>' + JSON.stringify(newObject, 0, 4) + '</pre>');

+1

Nice Verwendung von Lookahead in Split Regexp. –

1

Warum wollen Sie das Attribut auf Camelcase in erster Linie zu konvertieren ..?Just do

function arrayToStructuredObject(obj,props){ 
    if (props.length){ 
    obj[props[0]] = props.length > 1 ? {} : value; 
    arrayToStructuredObject(obj[props.shift()],props); 
    } 
    return obj; 
} 

var props = "animation-jump-tremendous-pinky".split("-"), 
    value = "123", 
     obj = {}, 
    sobj = {}; 
sobj = arrayToStructuredObject(obj, props); 

Neben i erinnern möchte, dass die Klammer-Notation mit einer Eigenschaft zu erstellen ist nur möglich, wenn der Verweis, dass die Halterung Notation auf verwendet wird, wird als Objekt vorgegeben. Wie

var o1; // <- undefined 
o1["myProp"] = 1; // Uncaught TypeError: Cannot set property 'myProp' of undefined 

während

var o2 = {}; // Object {} 
o2["myProp"] = 1; // <- 1 

dann wieder

o2["myProp"]["myOtherProp"] = 2; // <- 2 but won't type coerce o2.myProp to Object 

So von Vorschlägen gesprochen, bin ich, wenn unter Verwendung von Dirac-Notation direkt über undefinierte Variablen noch nicht sicher, wie eine andere Objekterstellung Muster macht Sinn oder nicht.

Nun, in jedem Fall eine vollständige Lösung wäre

var inp = {"personName" : "Grant", "animationJump" : "123", "fancyGirlTakesARide" : "987"}, 
result = Object.keys(inp).reduce(function(p,c,i){ 
            var props = c.replace(/[A-Z]/g, m => "-" + m.toLowerCase()).split("-"); 
            return arrayToStructuredObject(p,props,inp[c])      
            },{}); 

function arrayToStructuredObject(obj,props,val){ 
    if (props.length){ 
    obj[props[0]] = props.length > 1 ? {} : val; 
    arrayToStructuredObject(obj[props.shift()],props,val); 
    } 
    return obj; 
} 

sein Obwohl ich von einem Vorgriff der Methode der Aufteilung der Camelcase Requisiten liebte (/?=[A-Z]/) dauert es eine zusätzliche Aufgabe der unteren Gehäuse der ganze Reihe von Requisitenketten unabhängig davon, ob sie bereits Kleinbuchstaben sind oder nicht. Also ich denke, das könnte etwas schneller sein. (..oder nicht wegen der rekursiven Natur davon)

+0

Ich benutze AngularJS, die Bindestrichattribute in camelCase umwandelt –

+0

@Luke T O'Brien Nun, falls du dich definitiv mit camelCase Requisiten beschäftigen musst, dann habe ich meine Lösung in eine komplette geändert. – Redu

Verwandte Themen