假设我有一个表示对象中键的字符串。这是一个例子:
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
)。
如果该键是字符串,我如何设置对象中属性的值?
答案 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));