Gibt es eine einfache Möglichkeit, Objekten automatisch Eigenschaften hinzuzufügen, wenn diese noch nicht vorhanden sind?
Betrachten Sie das folgende Beispiel:
var test = {}
test.hello.world = "Hello doesn't exist!"
Dies funktioniert nicht, weil hello
es nicht definiert ist.
Der Grund, warum ich dies frage, ist, dass ich einige vorhandene Objekte habe, für die ich nicht weiß, ob sie bereits vorhanden sind hello
oder nicht. Ich habe tatsächlich viele dieser Objekte in verschiedenen Teilen meines Codes. Es ist sehr ärgerlich, immer zu überprüfen, ob es hello
existiert und ob kein neues Objekt erstellt wird wie:
var test = {}
if(test.hello === undefined) test.hello = {}
test.hello.world = "Hello World!"
Gibt es eine Möglichkeit, ein Objekt wie hello
in diesem Beispiel automatisch zu erstellen ?
Ich meine so etwas in PHP:
$test = array();
$test['hello']['world'] = "Hello world";
var_dump($test);
Ausgabe:
array(1) {
["hello"]=>
array(1) {
["world"]=>
string(11) "Hello world"
}
}
Ok, es ist ein Array, aber in js Arrays ist es das gleiche Problem wie bei Objekten.
quelle
x
im Bereich derexistcheckthingy
Funktion erstellt, das dann jedoch nicht an dastest
Objekt angehängt wird. Sie können es besser machen, indem Sie die "Array-ähnliche" Notation verwenden:existcheckthingy(a,x,y,z) { if (a[x] === undefined) a[x] = {}; a[x][y] = z;}
Antworten:
var test = {}; test.hello = test.hello || {}; test.hello.world = "Hello world!";
Wenn
test.hello
es nicht definiert ist, wird es auf ein leeres Objekt gesetzt.Wenn
test.hello
zuvor definiert, bleibt es unverändert.var test = { hello : { foobar : "Hello foobar" } }; test.hello = test.hello || {}; test.hello.world = "Hello World"; console.log(test.hello.foobar); // this is still defined; console.log(test.hello.world); // as is this.
quelle
Neues Objekt
rekursive Funktion
function addProps(obj, arr, val) { if (typeof arr == 'string') arr = arr.split("."); obj[arr[0]] = obj[arr[0]] || {}; var tmpObj = obj[arr[0]]; if (arr.length > 1) { arr.shift(); addProps(tmpObj, arr, val); } else obj[arr[0]] = val; return obj; }
Nennen Sie es mit einer punktnotierten Zeichenfolge
addProps(myObj, 'sub1.sub2.propA', 1);
oder mit einem Array
addProps(myObj, ['sub1', 'sub2', 'propA'], 1);
und Ihr Objekt wird so aussehen
myObj = { "sub1": { "sub2": { "propA": 1 } } };
Es funktioniert auch mit nicht leeren Objekten!
quelle
Nun, Sie könnten den Prototyp von
Object
um eine Funktion erweitern, die eine Eigenschaft zurückgibt, diese aber zuerst hinzufügt, wenn sie nicht vorhanden ist:Object.prototype.getOrCreate = function (prop) { if (this[prop] === undefined) { this[prop] = {}; } return this[prop]; }; var obj = {}; obj.getOrCreate("foo").getOrCreate("bar").val = 1;
quelle
Ohne eine Funktion ist dies nicht möglich, da JavaScript keine generische Getter / Setter-Methode für Objekte hat (z. B. Python
__getattr__
). Hier ist eine Möglichkeit, dies zu tun:function add_property(object, key, value) { var keys = key.split('.'); while (keys.length > 1) { var k = keys.shift(); if (!object.hasOwnProperty(k)) { object[k] = {}; } object = object[k]; } object[keys[0]] = value; }
Wenn Sie wirklich möchten, können Sie es dem Prototyp von hinzufügen
Object
. Sie können es so nennen:> var o = {} > add_property(o, 'foo.bar.baz', 12) > o.foo.bar.baz 12
quelle
read_property(o, 'foo.bar.baz')
12 zurückgeben wird? nachdem eine Eigenschaft hinzugefügt wurdeHier ist eine coole Version mit Proxies:
const myUpsert = (input) => { const handler = { get: (obj, prop) => { obj[prop] = obj[prop] || {}; return myUpsert(obj[prop]); } }; return new Proxy(input, handler); };
Und du benutzt es so:
myUpsert(test).hello.world = '42';
Dadurch werden alle fehlenden Eigenschaften als leere Objekte hinzugefügt und die vorhandenen bleiben unberührt. Es ist wirklich nur eine Proxy-Version des Klassikers
test.hello = test.hello || {}
, wenn auch viel langsamer ( siehe Benchmark hier ). Aber es ist auch viel schöner anzusehen, besonders wenn Sie es mehr als eine Ebene tiefer machen. Ich würde es nicht für leistungsintensives Daten-Crunching auswählen, aber es ist wahrscheinlich schnell genug für ein Front-End-Status-Update (wie in Redux).Beachten Sie, dass es hier einige implizite Annahmen gibt:
test.hello
zum Beispiel ersticken, wenn es sich um eine Zeichenfolge handelt.Diese können ziemlich leicht gemildert werden, wenn Sie sie nur in gut begrenzten Kontexten (wie einem Reduzierungskörper) verwenden, in denen die Wahrscheinlichkeit gering ist, dass der Proxy versehentlich zurückgegeben wird, und nicht viel anderes, was Sie mit dem Objekt tun möchten.
quelle
var test = {} if(!test.hasOwnProperty('hello')) { test.hello = {}; } test.hello.world = "Hello World!"
quelle
Dadurch wird eine Eigenschaft hinzugefügt,
hello
deren Wert{world: 'Hello world!'}
dem Testobjekt entspricht, falls es nicht vorhanden ist. Wenn Sie viele dieser Objekte haben, können Sie sie einfach durchlaufen und diese Funktion anwenden. Hinweis: Verwendet lodash.jsvar test = {}; _.defaults(test, { hello: {world: 'Hello world!'} });
Welches ist eigentlich eine bequeme Methode, um zu sagen:
var defaults = _.partialRight(_.assign, function(a, b) { return typeof a == 'undefined' ? b : a; }); defaults(test, { hello: {world: 'Hello world!'} });
Hinweis:
_.defaults
Verwendet Schleifen, um dasselbe wie beim zweiten Block zu erreichen.PS Checkout https://stackoverflow.com/a/17197858/1218080
quelle
Ich habe mir etwas ausgedacht, das auch wirklich benutzerdefiniert ist, aber es funktioniert soweit ich es getestet habe.
function dotted_put_var(str,val) { var oper=str.split('.'); var p=window; for (var i=0;i<oper.length-1;i++) { var x=oper[i]; p[x]=p[x]||{}; p=p[x]; } p[oper.pop()]=val; }
Dann kann eine komplexe Variable wie folgt festgelegt werden, um sicherzustellen, dass alle Links erstellt werden, wenn nicht bereits:
dotter_put_var('test.hello.world', 'testvalue'); // test.hello.world="testvalue";
Siehe diese funktionierende FIDDLE .
quelle
Ich benutze das:
Object.prototype.initProperty = function(name, defaultValue) { if (!(name in this)) this[name] = defaultValue; };
Sie können später zB tun:
var x = {a: 1}; x.initProperty("a", 2); // will not change property a x.initProperty("b", 3); // will define property b console.log(x); // => {a: 1, b: 3}
quelle
var test = {} test.hello.world = "Hello doesn't exist!"
Dies wird offensichtlich einen Fehler auslösen, da Sie die Datei test.hello nicht definiert haben
Zuerst müssen Sie den Hallo-Schlüssel definieren, dann können Sie im Inneren einen beliebigen Schlüssel zuweisen. Wenn Sie jedoch einen Schlüssel erstellen möchten, falls dieser nicht vorhanden ist, können Sie Folgendes tun
Mit der obigen Anweisung wird das test.hello-Objekt erstellt, wenn es nicht definiert ist. Wenn es definiert ist, wird derselbe Wert wie zuvor zugewiesen
Jetzt können Sie einen neuen Schlüssel in der Datei test.hello zuweisen
test.hello.world = "Everything works perfect"; test.hello.world2 = 'With another key too, it works perfect';
quelle
let test = {}; test = {...test, hello: {...test.hello, world: 'Hello does exist!'}}; console.log(test);
Wenn Sie den Spread-Operator verwenden, kann der Wert undefiniert sein. Es wird automatisch ein Objekt erstellt.
quelle
Ich habe einige Änderungen an der Antwort von Columbus vorgenommen , um das Erstellen von Arrays zu ermöglichen:
function addProps(obj, arr, val) { if (typeof arr == 'string') arr = arr.split("."); var tmpObj, isArray = /^(.*)\[(\d+)\]$/.exec(arr[0]) if (isArray && !Number.isNaN(isArray[2])) { obj[isArray[1]] = obj[isArray[1]] || []; obj[isArray[1]][isArray[2]] = obj[isArray[1]][isArray[2]] || {} tmpObj = obj[isArray[1]][isArray[2]]; } else { obj[arr[0]] = obj[arr[0]] || {}; tmpObj = obj[arr[0]]; } if (arr.length > 1) { arr.shift(); addProps(tmpObj, arr, val); } else obj[arr[0]] = val; return obj; } var myObj = {} addProps(myObj, 'sub1[0].sub2.propA', 1) addProps(myObj, 'sub1[1].sub2.propA', 2) console.log(myObj)
Ich denke, dass es möglich ist, mit "sub1 []. Sub2 ..." nur in das
sub1
Array zu pushen , anstatt den Index anzugeben, aber das reicht mir jetzt.quelle