JavaScript 객체 키 값 코딩. 중첩 값을 동적으로 설정합니다
-
20-09-2019 - |
문제
나는 객체와 함께 기본적인 키 가치 코딩을 할 수있는 작은 라이브러리에서 작업하고 있습니다. 다음과 같은 개체가 있다고 말합니다.
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 = val
와 같다 obj['prop'] = val
따라서 SetData를 다음과 같이 다시 작성할 수 있습니다.
var setData = function (path, value) {
data[path] = value;
};
그리고 그렇게해야합니다.
그러나 나는 당신이 3 레벨에서 얼마나 많은 성공을 거둘 수 있는지 잘 모르겠습니다. obj [ 'prop'] [ 'prop'], setData를 다시 작성하려면 다시 작성해야합니다. 그래도 운이 좋지 않습니다.
편집 : 나는 (나를 위해) 당신이 원하는 방식으로 중첩 된 것을 만들었지 만 그 이상은 아닙니다. 불행히도, 당신이 당신의 예보다 더 깊이 둥지를두고 있다면, 나는 버려야 할 진짜 이유가 없습니다. eval
. 나는 벤치 마크를 수행하지 않았지만 어느 시점에서 계산은 심지어보다 계산이 더 비싸다. eval
(성취하기가 꽤 어렵습니다.)
이것이 내가 생각해 낸 것입니다. 즉, 그것은 함께 작동합니다 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}});
당신은 단순히 두 번째 arg로 되풀이됩니다 setData
값을 찾을 때까지 전화하십시오. 당신이 되풀이 할 때마다, 당신은 data
지정된 지점에서 나무.
이 함수는 지정한 DOT 표기법을 수락하기 위해 쉽게 수정할 수 있지만, 나에게 이것은 더 깨끗하고 자연스러운 접근법입니다 (플러스, 스트링 OPS는 느립니다).
건배