Is there an easy way to automatically add properties to objects if they don\'t allready exist?
Consider the following example:
var test = {}
test.hel
You won't be able to do this without some sort of function, as JavaScript doesn't have a generic getter/setter method for objects (Python, for example, has __getattr__
). Here's one way to do it:
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;
}
If you really want to, you could add it to the prototype of Object
. You can call it like so:
> var o = {}
> add_property(o, 'foo.bar.baz', 12)
> o.foo.bar.baz
12
I've come up with something, really custom as well, but it works as far as I have tested.
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;
}
Then, a complex variable can be set like this, ensuring that every links will be created if not already:
dotter_put_var('test.hello.world', 'testvalue'); // test.hello.world="testvalue";
See this working FIDDLE.
let test = {};
test = {...test, hello: {...test.hello, world: 'Hello does exist!'}};
console.log(test);
When using the spread operator, the value can be undefined, it'll automatically create an object.
This will add a property hello
whose value is {world: 'Hello world!'}
to the test object, if it doesn't exist. If you have a lot of these objects, you can just iterate over them and apply this function. Note: uses lodash.js
var test = {};
_.defaults(test, { hello: {world: 'Hello world!'} });
Which is actually a convenience method for saying:
var defaults = _.partialRight(_.assign, function(a, b) {
return typeof a == 'undefined' ? b : a;
});
defaults(test, { hello: {world: 'Hello world!'} });
Note: _.defaults
uses loops to achieve the same thing as the second block.
P.S. Checkout https://stackoverflow.com/a/17197858/1218080
I use this:
Object.prototype.initProperty = function(name, defaultValue) {
if (!(name in this)) this[name] = defaultValue;
};
You can later do f.e.:
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}
I've made some changes on columbus's answer to allow create arrays:
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)
I think that is possible to allow use "sub1[].sub2..." to just push into the sub1
array, instead of specify the index, but that's enough for me now.