繁体   English   中英

Javascript对象键值编码。 动态设置嵌套值

[英]Javascript object key value coding. Dynamically setting a nested value

我正在开发一个小库,可以让我用对象做一些基本的键值编码。 说我有以下对象:

var data = { key1: "value1", key2: { nested1: 1, nested2: "wowza!" } };

我有以下JavaScript函数:

var setData = function(path, value) {
    eval("data." + path + "= value;");
};

在使用中:

setData("key1", "updated value1"); // data.key1 == "updated value1"
setData("key2.nested1", 99); // data.key2.nested1 == 99

这有效,但我想在不使用eval情况下完成上述操作。 这是可能的,还是eval最好的方式?

编辑:

注意可以假设您设置的值存在,至少对于路径深度 - 1.我更关心设置现有对象的值。

递归是你需要的:

function setData(key,val,obj) {
  if (!obj) obj = data; //outside (non-recursive) call, use "data" as our base object
  var ka = key.split(/\./); //split the key by the dots
  if (ka.length < 2) { 
    obj[ka[0]] = val; //only one part (no dots) in key, just set value
  } else {
    if (!obj[ka[0]]) obj[ka[0]] = {}; //create our "new" base obj if it doesn't exist
    obj = obj[ka.shift()]; //remove the new "base" obj from string array, and hold actual object for recursive call
    setData(ka.join("."),val,obj); //join the remaining parts back up with dots, and recursively set data on our new "base" obj
  }    
}

setData("key1", "updated value1"); // data.key1 == "updated value1"
setData("key2.nested1", 99); // data.key2.nested1 == 99

是的,这很容易。 obj.prop = valobj['prop'] = val所以你可以重写setData:

var setData = function (path, value) {
    data[path] = value;
};

这应该做到这一点。

但是,我不确定你对第3级有多大的成功(如果有意义的话。)obj.prop.prop不能被obj ['prop.prop']引用,而是必须被引用obj ['prop'] ['prop'],因此必须重写setData以将其考虑在内。 不过,我没有太多运气。

编辑:我做了一个(对我来说)设置它嵌套你想要的,但没有比这更多。 不幸的是,如果你的嵌套比你的例子更深,那么我没有看到放弃eval的真正原因。 我没有做任何基准测试,但在某些时候,计算的计算成本甚至比eval更高(这很难实现。)

这就是我提出的,它将至少设置为1'级别; 也就是说,它可以使用key2.nested1而不是key2.nested1.i_love_nesting ,如果这是有道理的:

var setData = function (path, value) {
    if (path.indexOf('.') != -1) {
        path = path.split('.');
        for (var i = 0, l = path.length; i < l; i++) {
            if (typeof(data[path[i]]) === 'object') {
                continue;
            } else {
                data[path[i - 1]][path[i]] = value;
            }
        }
    } else {
        data[path] = value;
    }
};

希望这可以帮助。 我可能没有以最有效的方式写这个,但......

灵感来自@ user1416920我做了这个:

function setData(key,val,obj)
{
    keys = key.split(/\./);
    last = keys.pop();

    keys.forEach(function(key)
    {
      if(typeof obj[key] === "undefined")
        obj[key] = {}; 
      obj = obj[key]; 
    });

    obj[last] = val;
}

它做的是非常自我解释^^。

function setData(key,val,obj){
    keys = key.split(/\./);
    to_set = keys.pop();
    keys.forEach(function(obj_name){ obj = obj[obj_name]; });
    obj[to_set] = val;
}

如果您可以灵活地指定路径,我认为这个问题变得更容易,更自然。 如果不是像key2.nested1这样做,你可以做{key2:{nested1:{}}} (对象表示法),它变得相当简单:

function setData(subtree, path){
    var nodeName = Object.keys(path);

    if(typeof path[nodeName] == 'object')
        setData(subtree[nodeName], path[nodeName]);
    else
        subtree[nodeName] = path[nodeName];
}

var data = { key1: "value1", key2: { nested1: 1, nested2: "wowza!" } };

// For the initial call, 'subtree' is the full data tree
setData(data, {key2:{nested1:99}});

您只是递归到setData调用的第二个arg,直到找到该值。 每次递归时,您都会进入指定点的data树。

可以很容易地修改此函数以接受您指定的点符号,但对我来说这是一种更清晰,更自然的方法(另外,String ops很慢)。

干杯

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM