使用字符串作为键设置对象的值

Set value of object using a string as the key

本文关键字:设置 对象 字符串      更新时间:2023-09-26

假设我有一个表示对象中键的字符串。这里有一个例子:

var obj = {
    test: 12,
    high: {
      sky: {
        val: 14
      }
    },
    low: [1, 2, 3]
},
keys = 'high.sky.val';

因此,我想设置obj.high.sky.val的值('high.sky.val'在字符串中)。

我知道如何读取值(不过,这可能不是最好的方法):

var keyPieces = keys.split('.'), value = obj;
keyPieces.forEach(function(x){
   value = value[x];
});
console.log(value); // 14

我不知道如何设置obj.high.sky.val(不使用eval)。

如果键是字符串,我如何设置对象中属性的值?

只是为了好玩:

function setKey(key, value, targetObject) {
  var keys = key.split('.'), obj = targetObject || window, keyPart;
  while ((keyPart = keys.shift()) && keys.length) {
    obj = obj[keyPart];
  }
  obj[keyPart] = value;
}

编辑:以前的版本不适用于"无点"键。。。固定的

在GameMaker中工作时,我实际上必须制作几个函数来实现这一目的:HTML5

function js_get(varname) {
    if( varname.indexOf(".") < 0)
        return window[varname];
    else {
        var curr = window, steps = varname.split("."), next;
        while(next = steps.shift()) curr = curr[next];
        return curr;
    }
}
function js_set(varname,value) {
    if( varname.indexOf(".") < 0)
        window[varname] = value;
    else {
        var curr = window, steps = varname.split("."), next, last = steps.pop();
        while(next = steps.shift()) curr = curr[next];
        curr[last] = value;
    }
}

这是因为对象在JS中是通过引用传递的。

您可以使用一对函数来设置和获取值。我只是举了一个例子。

objGet接受一个对象和密钥串。它将尝试获取值。如果找不到它,它将返回undefined。

objSet接受一个对象、关键字字符串和值。它将尝试查找并设置该值。如果不能(因为键字符串不正确),它将返回undefined。否则,它将返回传递的值。

function objGet(obj, keyString) {
    for(var keys = keyString.split('.'), i = 0, l = keys.length; i < l; i++) {
        obj = obj[keys[i]];
        if(obj === undefined) return undefined;
    }
    return obj;
}
function objSet(obj, keyString, val) {
    for(var keys = keyString.split('.'), i = 0, l = keys.length; i < l - 1; i++) {
        obj = obj[keys[i]];
        if(obj === undefined) return undefined;
    }
    if(obj[keys[l - 1]] === undefined) return undefined;
    obj[keys[l - 1]] = val;
    return val;
}

//// TESTING
var obj = {
    test: 12,
    high: {
        sky: {
            val: 14
        }
    },
    low: [1, 2, 3]
};
objGet(obj, 'test'); // returns 12
objGet(obj, 'high.sky.val'); // returns 14
objGet(obj, 'high.sky.non.existant'); // returns undefined
objSet(obj, 'test', 999); // return 999
obj.test; // 999
objSet(obj, 'high.sky.non.existant', 1234); // returns undefined
obj.high.sky; // { val: 14 }
objSet(obj, 'high.sky.val', 111); // returns 111
obj.high.sky; // { val: 111 }
function setDeep(el, key, value) {
    key = key.split('.');
    var i = 0, n = key.length;
    for (; i < n-1; ++i) {
        el = el[key[i]];
    }
    return el[key[i]] = value;
}
function getDeep(el, key) {
    key = key.split('.');
    var i = 0, n = key.length;
    for (; i < n; ++i) {
        el = el[key[i]];
    }
    return el;
}

你可以这样使用它:

setDeep(obj, 'high.sky.val', newValue);

我认为这是一个重要的问题,我需要一个变体,它允许在对象中嵌套数组,并用于深度创建不存在的字段。我知道你指定了"对象",但实际上对象也可以包含数组。在这种情况下,@Marshall的优秀代码并没有帮助我。所以我开始摆弄,得到了以下代码(希望这能帮助到任何人):

function objGet(obj, keyString) {
    // allow for arrays, returns undefined for non-existant-fields.
    var keys=[{label:"",type:"field",is_array:false}], current_key=0;
    for(var i=0;i<keyString.length;i++)
{
        var c=keyString.charAt(i);
        switch(c)
        {
            case ".":
                current_key++;
                keys[current_key]={label:"",type:"field",is_array:false};
            break;
            case "[":
                keys[current_key].is_array=true;
                current_key++;
                keys[current_key]={label:"",type:"index",is_array:false};
            break;
            case "]": 
            break;
            default:
                keys[current_key].label+=c;
        }
    }
    var part=obj;
    for(i = 0; i < keys.length; i++) 
    {
        var label=keys[i].label;
        if(i==keys.length-1)
        {
            return part[label];
            }else{
            if(part[label] === undefined)
            {
                    return undefined;
                }
                part = part[label];
            }
        }
    }
function objSet(obj, keyString, val) {
// allows for arrays, deep creates non-existant fields.
    var keys=[{label:"",type:"field",is_array:false}], current_key=0;
    for(var i=0;i<keyString.length;i++)
    {
        var c=keyString.charAt(i);
        switch(c)
        {
            case ".":
                current_key++;
                keys[current_key]={label:"",type:"field",is_array:false};
            break;
            case "[":
                keys[current_key].is_array=true;
                current_key++;
                keys[current_key]={label:"",type:"index",is_array:false};
            break;
        case "]": 
        break;
            default:
            keys[current_key].label+=c;
        }
    }
    var part=obj;
    for(i = 0; i < keys.length; i++) 
    {
        var label=keys[i].label;
        if(i==keys.length-1)
        {
            part[label] = val;
    }else{
        if(part[label] === undefined)
        {
            // we need to create it for deep set!
            if(keys[i].is_array)
            {
                part[label]=[];
            }else{
                part[label]={};
            }
        }
            part = part[label];
        }
    }
}
// TESTS
var obj = {
    test: 12,
    high: {
        sky: {
            val: 14
        }
    },
    kneedeep: [
                {something:"som0",something_else:"elze0"},
                {something:"som1",something_else:"elze1"}
              ],
    low: [1, 2, 3]
};
var obj_str=JSON.stringify(obj);
console.log("testing with object: "+obj_str);
 // TEST GET
console.log("test: "+objGet(obj, 'test')); // returns 999
console.log("high.sky.non.existant: "+objGet(obj, 'high.sky.non.existant')); // returns undefined
console.log("kneedeep[0].something: "+objGet(obj, 'kneedeep[0].something')); // returns "som0"
console.log("kneedeep[1].something_else: "+objGet(obj, 'kneedeep[1].something_else')); // returns "elze1"
console.log("high.sky.val: "+objGet(obj, 'high.sky.val')); // returns 14
console.log("low[0]: "+objGet(obj, 'low[0]')); // returns  1

  // TEST SET
objSet(obj, 'test', 999); // return 999
console.log("result SET 'test', 999:");
console.log(JSON.stringify(obj));
obj=JSON.parse(obj_str); // reset the object
objSet(obj, 'high.sky.non.existant', 1234); // creates the necessary objects.
console.log("result SET 'high.sky.non.existant', 1234:");
console.log(JSON.stringify(obj));
obj=JSON.parse(obj_str); // reset the object
objSet(obj, 'high.sky.val', 111); 
console.log("result SET 'high.sky.val', 111:");
console.log(JSON.stringify(obj));
obj=JSON.parse(obj_str); // reset the object
objSet(obj, 'kneedeep[0].something', 111); 
console.log("result SET 'kneedeep[0].something', 111:");
console.log(JSON.stringify(obj));
obj=JSON.parse(obj_str); // reset the object
objSet(obj, 'kneedeep[1].something_else', 1234); 
console.log("result SET 'kneedeep[1].something_else', 1234:");
console.log(JSON.stringify(obj));