Javascript 如何自动向未定义的对象添加属性?

Javascript 如何自动向未定义的对象添加属性?,javascript,Javascript,如果对象不存在,是否有一种简单的方法可以自动向对象添加属性 考虑以下示例: var test={} test.hello.world=“hello不存在!” 这不起作用,因为未定义hello 我问这个问题的原因是因为我有一些现有的对象,我不知道它们是否都准备好了hello。实际上,我在代码的不同部分中有很多这样的对象。 总是检查hello是否存在,以及是否没有创建新对象(如: var test={} 如果(test.hello==未定义)test.hello={} test.hello.wor

如果对象不存在,是否有一种简单的方法可以自动向对象添加属性

考虑以下示例:

var test={}
test.hello.world=“hello不存在!”
这不起作用,因为未定义
hello

我问这个问题的原因是因为我有一些现有的对象,我不知道它们是否都准备好了
hello
。实际上,我在代码的不同部分中有很多这样的对象。 总是检查
hello
是否存在,以及是否没有创建新对象(如:

var test={}
如果(test.hello==未定义)test.hello={}
test.hello.world=“hello world!”
在本例中,是否有一种方法可以自动创建像
hello
这样的对象

我在php中的意思是类似的:

$test=array();
$test['hello']['world']=“hello world”;
var_dump($测试);
输出:

数组(1){
[“hello”]=>数组(1){
[“世界”]=>字符串(11)“你好,世界”
}
}
好的,这是一个数组,但在js数组中,这和对象的问题是一样的

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.

如果没有某种函数,您将无法做到这一点,因为JavaScript没有用于对象的通用getter/setter方法(例如,Python具有
\uuuuuu getattr\uuuu
)。这里有一种方法:

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;
}
如果确实需要,可以将其添加到
对象的原型中。你可以这样称呼它:

> var o = {}
> add_property(o, 'foo.bar.baz', 12)
> o.foo.bar.baz
12

我已经想出了一些东西,真正的自定义以及,但它的工作,因为我已经测试

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;
}

查看此操作。

这将向测试对象添加一个属性
hello
,其值为
{world:'hello world!'}
,如果该属性不存在。如果你有很多这样的对象,你可以迭代它们并应用这个函数。注:用途

这实际上是一个方便的说法:

var defaults = _.partialRight(_.assign, function(a, b) {
  return typeof a == 'undefined' ? b : a;
});        
defaults(test, { hello: {world: 'Hello world!'} });
注意:
\默认值
使用循环实现与第二个块相同的功能


p.S.Checkout

您可以使用返回属性的函数扩展
对象的原型,但如果不存在,则首先添加属性:

Object.prototype.getOrCreate = function (prop) {
    if (this[prop] === undefined) {
        this[prop] = {};
    }
    return this[prop];
};

var obj = {};

obj.getOrCreate("foo").getOrCreate("bar").val = 1;
新对象

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
    }
  }
};
它也适用于非空对象

我用这个:

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}
这将抛出一个错误,因为您没有定义测试。您好

test.hello.world = "Everything works perfect";

test.hello.world2 = 'With another key too, it works perfect';
首先你需要定义hello键,然后在里面你可以分配任何键。 但若你们想创建一个不存在的密钥,那个么你们可以做下面的事情

test.hello = test.hello || {};
上面的语句将创建test.hello对象(如果未定义),如果已定义,则将分配与以前相同的值

现在,您可以在测试中分配任何新密钥。hello

test.hello.world = "Everything works perfect";

test.hello.world2 = 'With another key too, it works perfect';

这是一个带有代理的酷版本:

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 |{}
的一个代理版本,虽然速度要慢得多(.),但它看起来也更好,尤其是如果你要做一个以上的层次。我不会选择它进行高性能的数据处理,但它可能足够快,可以进行前端状态更新(如Redux)

请注意,这里有一些隐含的假设:

  • 中间的属性要么是对象,要么不存在。例如,如果
    test.hello
    是一个字符串,这将阻塞
  • 只要您使用代理而不是原始对象,您就始终希望这样做
  • 如果您仅在边界良好的上下文(如reducer body)中使用它,那么就很容易缓解这些问题,因为在这些上下文中,意外返回代理的可能性很小,而您不想对对象执行其他操作。

    let test={};
    test={…test,hello:{…test.hello,world:'hello确实存在!'};
    控制台日志(测试)我对进行了一些更改以允许创建阵列:

    函数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]];
    }否则{
    obj[arr[0]]=obj[arr[0]]| |{};
    tmpObj=obj[arr[0]];
    }
    如果(arr.length>1){
    arr.shift();
    addProps(tmpObj、arr、val);
    }否则
    obj[arr[0]]=val;
    返回obj;
    }
    var myObj={}
    addProps(myObj,'sub1[0]。sub2.propA',1)
    addProps(myObj,'sub1[1]。sub2.propA',2)
    
    console.log(myObj)
    您可以使用逻辑空赋值(??=):


    我认为最简单的方法是使用Lodash

    \.set({},'a[0].b.c',4);
    //=>{a:[{b:{c:4}}]}
    
    函数existcheckthingy(x,y,z){if(x==未定义)x={};x.y=z;}用作existcheckthingy(test.hello,world,“hello不存在!”)@鲍比,那不行。它将在
    existcheckthingy
    函数的范围内创建一个新对象
    x
    ,但该对象随后不会附加到
    test
    对象。使用“类似数组”的表示法可以做得更好:
    existcheckthingy(a,x,y,z){if(a[x]==undefined)a[x]={};a[x][y]=z;}
    可能的重复:@Jeff oops,忘记了:3考虑lodash'set',这是非常惯用的JSIt,非常感谢。但这仍然是一个手动检查。不可能没有吗?@MarcelGwerder不,这是最短的了。@MarcelGwerder:据我所知不是。@xbonez NB:没有“定义”-truthy。霍
    test.hello.world = "Everything works perfect";
    
    test.hello.world2 = 'With another key too, it works perfect';
    
    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';
    
    var test = {};
    (test.hello ??= {}).world ??= "Hello doesn't exist!";