Javascript对象键值编码。动态设置嵌套值
我正在开发一个小库,它可以让我对对象进行一些基本的键值编码。假设我有以下目标:Javascript对象键值编码。动态设置嵌套值,javascript,object,key-value-observing,key-value-coding,Javascript,Object,Key Value Observing,Key Value Coding,我正在开发一个小库,它可以让我对对象进行一些基本的键值编码。假设我有以下目标: var data = { key1: "value1", key2: { nested1: 1, nested2: "wowza!" } }; 我有以下JavaScript函数: var setData = function(path, value) { eval("data." + path + "= value;"); }; 在使用中: setData("key1", "updated value1"
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。我更关心的是设置现有对象的值。是的,这很简单
obj.prop=val
与obj['prop']=val
相同,因此您可以将setData重写为:
var setData = function (path, value) {
data[path] = value;
};
这应该可以做到
但是,我不确定您在第三级中会取得多大成功(如果有意义的话)。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;
}
};
var setData=函数(路径、值){
if(path.indexOf('.')!=-1){
path=path.split('.');
对于(变量i=0,l=path.length;i
希望这有帮助。我可能没有用最有效的方式写这篇文章,但是 递归是您需要的:
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
功能设置数据(按键、val、obj){
如果(!obj)obj=data;//外部(非递归)调用,请使用“data”作为基本对象
var ka=key.split(//\.//);//按点分割键
如果(ka.length<2){
obj[ka[0]]=val;//键中只有一个部分(没有点),只需设置值
}否则{
if(!obj[ka[0]])obj[ka[0]]={};//如果我们的“新”基础对象不存在,请创建它
obj=obj[ka.shift()];//从字符串数组中删除新的“base”obj,并保留实际对象以进行递归调用
setData(ka.join(“.”,val,obj);//用点连接其余部分,并递归地在新的“基本”obj上设置数据
}
}
设置数据(“键1”,“更新值1”);//data.key1==“更新的值1”
setData(“key2.nested1”,99);//data.key2.nested1==99
我认为,如果您能够灵活地指定路径,这个问题将变得更容易、更自然地解决。如果不执行类似于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
调用的第二个参数,直到找到值为止。每次递归时,您都会在指定的点下放到数据树中
这个函数也可以很容易地修改为接受您指定的点表示法,但对我来说,这是一种更干净、更自然的方法(另外,字符串运算速度很慢)
干杯灵感来自@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;
}
它所做的事情是不言自明的^^。不幸的是,这对嵌套值不起作用。在您的示例中:setData(“prop.nestedProp”、“val”);将产生以下数据json:{“prop.nestedProp”:“val”}我想要:{prop:{nestedProp:{nestedProp:val”}是的,我在提交帖子几秒钟后发现了这一点。我花了一点时间才得到一个很好的工作函数,但上面的那个应该可以。您的库的另一种选择可能是让他们直接访问“对象”,即让他们访问my_json\u object.foo.bar
。如果值发生更改,则完整函数(为简单起见排除)将触发事件<代码>app.dataSet=function(path,value){if(app.dataGet(path)==value)返回值;eval(“app.u数据”+path+“=value;”);app.trigger(“数据”+path);返回app.dataGet(path);}代码>不幸的是,这需要在任意深度工作。我希望有一个很好的解决方案来解决这个问题,让get函数(必须测试它是否比使用eval更快)。谢谢你的帮助。我希望我能投100票——这正是我想要的!非常感谢。非常感谢你!我无法告诉你这对我有多大帮助。这是一个很好的答案。我制作了一个没有
obj
参数的版本,并且为了清晰起见使用了ES6语法。非常感谢你。你救了我一天!
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;
}