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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13719593/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 12:43:59  来源:igfitidea点击:

How to set object property (of object property of..) given its string name in JavaScript?

javascriptstringpropertiesnested

提问by Chiel ten Brinke

Suppose we are only given

假设我们只得到

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

How can we set the property obj.foo.bar.foobarto a certain value (say "hello world")? So I want to achieve this, while we only have the property name in a string:

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

obj.foo.bar.foobar = "hello world";

回答by VisioN

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");

回答by Cerbrus

Since this question appears to be answered by incorrect answers, I'll just refer to the correct answer from a similar question

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

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

Use:

用:

var obj = {};
setDeepValue(obj, 'Hello World', 'foo.bar.foobar');

回答by Stephan B?nnemann-Walenta

edit: I've created a jsPerf.com testcaseto compare the accepted answer with my version. Turns out that my version is faster, especially when you go very deep.

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

http://jsfiddle.net/9YMm8/

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");

?

?

?

?

回答by Micha? Fr?czkiewicz

I know it's an old one, but I see only custom functions in answers.
If you don't mind using a library, look at lodash_.setand _.getfunction.

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

回答by Labithiotis

All solutions overid any of the original data when setting so I have tweaked with the following, made it into a single object too:

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

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

Can also change functions to be an Oject.prototype method changing obj param to this:

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

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

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

回答by Daniel Lizik

Here's one that returns the updated object

这是一个返回更新后的对象

function deepUpdate(value, path, tree, branch = tree) {
  const last = path.length === 1;
  branch[path[0]] = last ? value : branch[path[0]];
  return last ? tree : deepUpdate(value, path.slice(1), tree, branch[path[0]]);
}

const path = 'cat.dog';
const updated = deepUpdate('a', path.split('.'), {cat: {dog: null}})
// => { cat: {dog: 'a'} }

回答by Thiago Kroger

Here is a simple function to do that using reference.

这是一个简单的函数,可以使用引用来做到这一点。

    function setValueByPath (obj, path, value) {
        var ref = obj;

        path.split('.').forEach(function (key, index, arr) {
            ref = ref[key] = index === arr.length - 1 ? value : {};
        });

        return obj;
    }

回答by Nina Scholz

You could split the path and make a check if the following element exist. If not assign an object to the new property.

您可以拆分路径并检查以下元素是否存在。如果没有将对象分配给新属性。

Return then the value of the property.

然后返回该属性的值。

At the end assign the value.

最后赋值。

function setValue(object, path, value) {
    var fullPath = path.split('.'),
        way = fullPath.slice(),
        last = way.pop();

    way.reduce(function (r, a) {
        return r[a] = r[a] || {};
    }, object)[last] = value;
}

var object = {},
    propName = 'foo.bar.foobar',
    value = 'hello world';

setValue(object, propName, value);
console.log(object);

回答by Vitim.us

A very straightforward one.

很直接的一个。

No recursions or callbacks overhead.

没有递归或回调开销。

function setDeepVal(obj, path, val) {
  var props = path.split('.');
  for (var i = 0, n = props.length - 1; i < n; ++i) {
    obj = obj[props[i]] = obj[props[i]] || {};
  }
  obj[props[i]] = val;
  return obj;
}



// TEST
var obj = { hello : 'world' };
setDeepVal(obj, 'foo.bar.baz', 1);
setDeepVal(obj, 'foo.bar2.baz2', 2);
console.log(obj);

回答by Dieter Gribnitz

Here is a get and set function i just compiled from a couple of threads + some custom code.

这是我刚刚从几个线程 + 一些自定义代码编译的 get 和 set 函数。

It will also create keys that don't exist on set.

它还将创建现场不存在的密钥。

function setValue(object, path, value) {
    var a = path.split('.');
    var o = object;
    for (var i = 0; i < a.length - 1; i++) {
        var n = a[i];
        if (n in o) {
            o = o[n];
        } else {
            o[n] = {};
            o = o[n];
        }
    }
    o[a[a.length - 1]] = value;
}

function getValue(object, path) {
    var o = object;
    path = path.replace(/\[(\w+)\]/g, '.');
    path = path.replace(/^\./, '');
    var a = path.split('.');
    while (a.length) {
        var n = a.shift();
        if (n in o) {
            o = o[n];
        } else {
            return;
        }
    }
    return o;
}