最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

JavaScript: Change data in JSON by string data path - Stack Overflow

programmeradmin3浏览0评论

Let's say, I have the following JSON, which can be easily converted back and forth to a JavaScript object:

{
    "foo": {
        "bar": "Common substitute word",
        "baz": "Another mon substitute word",
        "questionWords": {
            "wat": "Inadequate question word",
            "wut": "Even more inadequate question word"
        }
    }
}

And I receive modifications regarding this JSON in another JSON file, like this:

{
    "foo.questionWords.wut": "A question word to avoid"
}

So the path to modify is given as a string. And I have to modify the first JSON by the new data.

But also the new data path possibly does not exist:

{
    "foo.callingWords.dude": "Commonly used synonym for pal"
}

And the new data path might have indeterminable depth:

{
    "who.knows.how.deep.we.will.go": "Look, a penny!"
}

What is the best way to handle this without a JS library, just by plain Vanilia JS?

(You can use the latest JavaScript features.)

Thank you for your help!

Let's say, I have the following JSON, which can be easily converted back and forth to a JavaScript object:

{
    "foo": {
        "bar": "Common substitute word",
        "baz": "Another mon substitute word",
        "questionWords": {
            "wat": "Inadequate question word",
            "wut": "Even more inadequate question word"
        }
    }
}

And I receive modifications regarding this JSON in another JSON file, like this:

{
    "foo.questionWords.wut": "A question word to avoid"
}

So the path to modify is given as a string. And I have to modify the first JSON by the new data.

But also the new data path possibly does not exist:

{
    "foo.callingWords.dude": "Commonly used synonym for pal"
}

And the new data path might have indeterminable depth:

{
    "who.knows.how.deep.we.will.go": "Look, a penny!"
}

What is the best way to handle this without a JS library, just by plain Vanilia JS?

(You can use the latest JavaScript features.)

Thank you for your help!

Share Improve this question asked Feb 26, 2018 at 6:23 Erik KrániczErik Kránicz 4071 gold badge4 silver badges13 bronze badges 2
  • 1 Is there anything you've tried yet? What's worked? What outputs have you managed to get? – SCB Commented Feb 26, 2018 at 6:30
  • Possible duplicate of Fastest way to flatten / un-flatten nested JSON objects – 0xtvarun Commented Feb 26, 2018 at 6:47
Add a ment  | 

5 Answers 5

Reset to default 7

Never use eval for tasks like this. Split your "path" and walk step-by-step:

var data = {
    "foo": {
        "bar": "Common substitute word",
        "baz": "Another mon substitute word",
        "questionWords": {
            "wat": "Inadequate question word",
            "wut": "Even more inadequate question word"
        }
    }
},

mods = {
  "foo.questionWords.wut": "A question word to avoid",
  "foo.callingWords.dude": "Commonly used synonym for pal",
  "who.knows.how.deep.we.will.go": "Look, a penny!"
};

function apply(data, mods) {
  for (var path in mods) {
    var k = data;
    var steps = path.split('.');
    var last = steps.pop();
    steps.forEach(e => (k[e] = k[e] || {}) && (k = k[e]));
    k[last] = mods[path];
  }
  return data
}

console.log(apply(data, mods))

One of the options in vanillaJS, you can use eval (but be afraid, very afraid!) like this:

var t = {
    "foo": {
        "bar": "Common substitute word",
        "baz": "Another mon substitute word",
        "questionWords": {
            "wat": "Inadequate question word",
            "wut": "Even more inadequate question word"
        }
    }
};

eval("t.foo.bar = 13")

Essentially the same as everybody's answer, just avoiding usage of eval(), if that could be a problem.

var obj={
    "foo": {
        "bar": "Common substitute word",
        "baz": "Another mon substitute word",
        "questionWords": {
            "wat": "Inadequate question word",
            "wut": "Even more inadequate question word"
        }
    }
}

var obj2={
    "foo.questionWords.wut": "A question word to avoid"
}

for(var i in obj2){
	  var res = i.split(".");
    var fieldName = res.splice(res.length-1,1);
    var objField = res.reduce((r, u) => r && r[u] ? r[u] : '' , obj);
    objField[fieldName]=obj2[i];
}
console.log(obj);

My solution using recursive function.

const modifyObject = (object, jsonPath, value) => {
  const keys = jsonPath.split(".");
  const key = keys.splice(0, 1);
  if (keys.length > 0) {
    modifyObject(object[key], keys.join('.'), value)
  } else {
    object[key] = value;
  }
}

const obj = {
  foo: {
    bar: 11,
    baz: 12,
    bac: {
      leng: 1,
      str: 'hello world'
    }
  }
};

modifyObject(obj, 'foo.bac.leng', 'modified');

console.log(JSON.stringify(obj));

In imperative style where I'm just mutating source:

updateAll = function(source, target) {
    Object.keys(target)
        .forEach((k) => update(source, k, target[k]));
}

update = function(source, targetKey, targetValue) {
var keys = targetKey.split('.');

    // Iterate as long as there are keys to shift out and as long as source is
    // defined for that key.
     while((key = keys.shift()) && source[key]) {

        // If we're at a leaf, assign new value. Otherwise, iterate further into
        // the object.
        if (keys.length === 0 && typeof source[key] !== 'object') {
            source[key] = targetValue;
        } else {
            source = source[key];
        }
    }
}
发布评论

评论列表(0)

  1. 暂无评论