如何在 JavaScript 中给定其字符串名称设置对象属性(...的对象属性)?

IT技术 javascript string properties nested
2021-01-28 09:53:00

假设我们只给

var obj = {};
var propName = "foo.bar.foobar";

我们如何将属性obj.foo.bar.foobar设置为某个值(比如“hello world”)?所以我想实现这一点,而我们只有一个字符串中的属性名称:

obj.foo.bar.foobar = "hello world";
6个回答
function assign(obj, prop, value) {
    if (typeof prop === "string")
        prop = prop.split(".");

    if (prop.length > 1) {
        var e = prop.shift();
        assign(obj[e] =
                 Object.prototype.toString.call(obj[e]) === "[object Object]"
                 ? obj[e]
                 : {},
               prop,
               value);
    } else
        obj[prop[0]] = value;
}

var obj = {},
    propName = "foo.bar.foobar";

assign(obj, propName, "Value");
这不适用于数组。模板[0].项目[0].格式.颜色
2021-03-25 09:53:00
@StephanBönnemann,如果它不是字符串,那么当我们需要设置属性时,我们就在迭代中 obj[prop[0]] = value;
2021-03-30 09:53:00
@StephanBönnemann 不确定你的意思。添加它是为了使解决方案通用,以便我们可以将数组或字符串作为prop.
2021-04-01 09:53:00
是的,当路径尚不存在时,此方法似乎也有效。
2021-04-03 09:53:00
为什么要检查 typeof 道具?无论如何,您都将继续执行功能流程。
2021-04-06 09:53:00

由于这个问题似乎是由错误答案回答的,我将参考类似问题中的正确答案

function setDeepValue(obj, value, path) {
    if (typeof path === "string") {
        var path = path.split('.');
    }

    if(path.length > 1){
        var p=path.shift();
        if(obj[p]==null || typeof obj[p]!== 'object'){
             obj[p] = {};
        }
        setDeepValue(obj[p], value, path);
    }else{
        obj[path[0]] = value;
    }
}

用:

var obj = {};
setDeepValue(obj, 'Hello World', 'foo.bar.foobar');
看起来我=typeof. 但坦率地说,这typeof是确保您不会试图拆分对象的唯一方法,这是我遇到的事情之一。剩下的就是简单的递归。
2021-03-11 09:53:00
嗯。你的答案看起来和我的一模一样:)
2021-03-14 09:53:00
@Cerbrus 还有一件事。如果 obj.foo.bar 被分配了一个值,然后我尝试 setDeepValue foo.bar.foobar 它失败并出现错误(除非值是 boolean false)。可能最安全的方法是测试 obj[p] 是否是一个对象。如果不是对象,请将其替换为 {}。由于 null 是一个对象,正确的测试应该是if(obj[p]!=null && typeof obj[p]=== 'object')
2021-03-16 09:53:00
如果我用foo.bar.foobarand调用它两次foo.bar2.foobar2怎么办?
2021-03-17 09:53:00
在那种情况下,它确实obj.foo在设置时reset foo.bar2.foobar2编辑了代码。oop,没有看到您建议的编辑,正在修复。
2021-03-31 09:53:00

我知道这是一个旧的,但我在答案中只看到自定义函数。
如果您不介意使用库,请查看lodash _.set_.get函数。

编辑:我创建了一个jsPerf.com 测试用例来将接受的答案与我的版本进行比较。事实证明,我的版本更快,尤其是当你深入时。

http://jsfiddle.net/9YMm8/

var nestedObjectAssignmentFor = function(obj, propString, value) {
    var propNames = propString.split('.'),
        propLength = propNames.length-1,
        tmpObj = obj;

    for (var i = 0; i <= propLength ; i++) {
        tmpObj = tmpObj[propNames[i]] = i !== propLength ?  {} : value;  
    }
    return obj;
}

var obj = nestedObjectAssignment({},"foo.bar.foobar","hello world");

仅适用于空的第一个参数对象,否则它会覆盖原始对象数据。
2021-03-15 09:53:00
@Cerbrus 似乎取决于浏览器,自己创建了测试用例jsperf.com/nested-object-assignment
2021-03-17 09:53:00
代码性能测试 101:不要每次迭代都初始化你的函数
2021-03-18 09:53:00
这在 Chrome 中似乎比建议的递归函数稍慢但是,它在 IE / FF 中要快得多(不过,Chrome 的迭代次数/秒最多,V8是执行 JavaScript 的野兽)
2021-04-01 09:53:00

所有解决方案在设置时都覆盖了任何原始数据,因此我对以下内容进行了调整,使其也成为单个对象:

 var obj = {}
 nestObject.set(obj, "a.b", "foo"); 
 nestObject.get(obj, "a.b"); // returns foo     

 var nestedObject = {
     set: function(obj, propString, value) {
         var propNames = propString.split('.'),
             propLength = propNames.length-1,
             tmpObj = obj;
         for (var i = 0; i <= propLength ; i++) {
             if (i === propLength){
                 if(tmpObj[propNames[i]]){
                     tmpObj[propNames[i]] = value;
                 }else{
                     tmpObj[propNames[i]] = value;
                 }
             }else{
                 if(tmpObj[propNames[i]]){
                     tmpObj = tmpObj[propNames[i]];
                 }else{
                     tmpObj = tmpObj[propNames[i]] = {};
                 }
             }
         }
         return obj;
     },
     get: function(obj, propString){
         var propNames = propString.split('.'),
             propLength = propNames.length-1,
             tmpObj = obj;
         for (var i = 0; i <= propLength ; i++) {
             if(tmpObj[propNames[i]]){
                 tmpObj = tmpObj[propNames[i]];
             }else{
                 break;
             }
         }
         return tmpObj;
     }
 };

也可以将函数更改为 Oject.prototype 方法,将 obj 参数更改为:

Object.prototype = { setNested = function(){ ... }, getNested = function(){ ... } } 

{}.setNested('a.c','foo')