如果对象尚未存在,是否有一种简单的方法可以自动添加属性?
考虑以下示例:
var test = {}
test.hello.world = "Hello doesn't exist!"
这不起作用,因为未定义hello
。
我问这个的原因是因为我有一些现有的对象,我不知道它们是否已经有hello
。实际上我在代码的不同部分有很多这些对象。
总是检查hello
是否存在以及是否不创建新对象非常烦人:
var test = {}
if(test.hello === undefined) test.hello = {}
test.hello.world = "Hello World!"
在这个例子中,有没有办法自动创建像hello
这样的对象?
我在php中的意思是这样的:
$test = array();
$test['hello']['world'] = "Hello world";
var_dump($test);
输出:
array(1) {
["hello"]=>
array(1) {
["world"]=>
string(11) "Hello world"
}
}
好吧,这是一个数组,但在js数组中,它与对象的问题相同。
答案 0 :(得分:102)
var test = {};
test.hello = test.hello || {};
test.hello.world = "Hello world!";
如果未定义test.hello
,则将其设置为空对象。
如果先前已定义test.hello
,则保持不变。
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.
答案 1 :(得分:11)
新对象
myObj = {};
递归函数
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;
}
用点标记字符串
调用它addProps(myObj, 'sub1.sub2.propA', 1);
或使用数组
addProps(myObj, ['sub1', 'sub2', 'propA'], 1);
,您的对象将如下所示
myObj = {
"sub1": {
"sub2": {
"propA": 1
}
}
};
它也适用于非空对象!
答案 2 :(得分:11)
您可以使用逻辑空赋值 (??=):
var test = {};
(test.hello ??= {}).world ??= "Hello doesn't exist!";
答案 3 :(得分:5)
如果没有某种功能,你将无法做到这一点,因为JavaScript没有对象的通用getter / setter方法(例如,Python有__getattr__
)。这是一种方法:
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;
}
如果您真的想要,可以将其添加到Object
的原型中。你可以这样称呼它:
> var o = {}
> add_property(o, 'foo.bar.baz', 12)
> o.foo.bar.baz
12
答案 4 :(得分:5)
您可以使用返回属性的函数扩展Object
的原型,但如果它不存在则先添加它:
Object.prototype.getOrCreate = function (prop) {
if (this[prop] === undefined) {
this[prop] = {};
}
return this[prop];
};
var obj = {};
obj.getOrCreate("foo").getOrCreate("bar").val = 1;
答案 5 :(得分:3)
这是一个带有代理的很酷的版本:
const myUpsert = (input) => {
const handler = {
get: (obj, prop) => {
obj[prop] = obj[prop] || {};
return myUpsert(obj[prop]);
}
};
return new Proxy(input, handler);
};
您可以这样使用它:
myUpsert(test).hello.world = '42';
这会将所有缺少的属性添加为空对象,并保持现有属性不变。它实际上只是经典test.hello = test.hello || {}
的代理版本,尽管速度较慢(See benchmark here。)但是它看起来也要好得多,尤其是如果您要进行一个以上级别的深入研究时。我不会选择它来进行性能繁重的数据处理,但是它对于前端状态更新(例如在Redux中)可能足够快。
请注意,这里有一些隐含的假设:
test.hello
是一个字符串,则会阻塞。如果仅在边界有限的环境(如化简器主体)中使用它,这些情况就很容易缓解,在这种情况下,意外返回代理的可能性很小,并且您不想对该对象做很多其他事情。
答案 6 :(得分:2)
这将向测试对象添加值hello
的属性{world: 'Hello world!'}
(如果它不存在)。如果你有很多这些对象,你可以迭代它们并应用这个函数。注意:使用lodash.js
var test = {};
_.defaults(test, { hello: {world: 'Hello world!'} });
这实际上是一种方便的说法:
var defaults = _.partialRight(_.assign, function(a, b) {
return typeof a == 'undefined' ? b : a;
});
defaults(test, { hello: {world: 'Hello world!'} });
注意:_.defaults
使用循环来实现与第二个块相同的东西。
答案 7 :(得分:2)
我认为最简单的方法是使用来自 Lodash 的 _.set
_.set({}, 'a[0].b.c', 4);
// => { a: [{ b: { c: 4 } }] }
答案 8 :(得分:1)
var test = {}
if(!test.hasOwnProperty('hello')) {
test.hello = {};
}
test.hello.world = "Hello World!"
答案 9 :(得分:1)
我想出了一些东西,也是真正习惯的东西,但是就我测试而言它起作用了。
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;
}
然后,可以像这样设置一个复杂的变量,确保每个链接都已创建,如果还没有:
dotter_put_var('test.hello.world', 'testvalue'); // test.hello.world="testvalue";
请参见此工作FIDDLE。
答案 10 :(得分:1)
var test = {}
test.hello.world = "Hello doesn't exist!"
由于您没有定义test.hello
,因此显然会抛出错误首先你需要定义hello键然后在里面你可以分配任何键。 但是如果你想创建密钥,如果不存在,那么你可以做以下事情
test.hello = test.hello || {};
如果没有定义,上面的语句将创建test.hello对象,如果定义了它,那么它将分配与之前相同的值
现在您可以在test.hello
中分配任何新密钥test.hello.world = "Everything works perfect";
test.hello.world2 = 'With another key too, it works perfect';
答案 11 :(得分:0)
我用这个:
Object.prototype.initProperty = function(name, defaultValue) {
if (!(name in this)) this[name] = defaultValue;
};
你以后可以做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}
答案 12 :(得分:0)
let test = {};
test = {...test, hello: {...test.hello, world: 'Hello does exist!'}};
console.log(test);
使用散布运算符时,该值可以是未定义的,它将自动创建一个对象。
答案 13 :(得分:0)
我对columbus's answer进行了一些更改,以允许创建数组:
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)
我认为可以允许使用“ sub1 []。sub2 ...”仅推入sub1
数组,而不是指定索引,但这对我来说已经足够了。