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

时间:2012-02-17 22:09:54

标签: javascript

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

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)。

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

5 个答案:

答案 0 :(得分:6)

只是为了好玩:

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

编辑:以前的版本不适用于“无点”键...已修复。

答案 1 :(得分:5)

在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中的引用传递的。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

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 }

答案 4 :(得分:0)

我认为这是一个重要的问题,我需要一个变体,该变体允许将数组嵌套在对象中并深度创建不存在的字段。 我知道您指定了“对象”,但实际上,一个对象也可以容纳数组。 在这种情况下,@ 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));