2

オブジェクトを使用して基本的なキー値のコーディングを行うことができる小さなライブラリに取り組んでいます。次のオブジェクトがあるとします。

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については、設定している値が存在すると想定できることに注意してください。既存のオブジェクトの値の設定についてもっと心配しています。

4

5 に答える 5

18

再帰はあなたが必要とするものです:

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
于 2010-01-14T02:38:52.533 に答える
4

ええ、簡単です。obj.prop = valと同じなobj['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 'level' の深さを設定します。つまり、それが理にかなっていれば、 では機能しますが、 では機能し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;
    }
};

お役に立てれば。私はこれを最も効率的な方法で書いていないかもしれませんが...

于 2010-01-14T00:16:13.943 に答える
1

@ 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;
}

それが何をするかは自明です^^。

于 2016-12-30T00:16:39.567 に答える
0
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;
}
于 2012-05-25T08:33:15.263 に答える