문제

나는 객체와 함께 기본적인 키 가치 코딩을 할 수있는 작은 라이브러리에서 작업하고 있습니다. 다음과 같은 개체가 있다고 말합니다.

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는 느립니다).

건배

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top