【问题标题】:Traverse down a JSON depending on length of array根据数组的长度遍历 JSON
【发布时间】:2017-07-11 17:22:44
【问题描述】:

假设我有一个 json

jsonData = {
   "id":"dfd",
   "properties":{
      "Pri":"2",
      "Brief Description":"asdf",
      "Description":"",
      "tree":{
        "var": "2",
        "rav": "3"
      }
    }   
}

还有一个列表

var variableArray = ['properties', 'tree', 'var'];

如果我想访问 var 的值并对其进行编辑。在保持 jsonData 的价值的同时,我将如何做到这一点?

我试过了

for (var i = 0; i < variableArray.length; i++) {
  jsonData = jsonData[variableArray[i]];
}
jsonData = 'new value';

但我无法再访问整个 jsonData。

有什么方法可以实现这个?

【问题讨论】:

标签: javascript jquery json for-loop


【解决方案1】:

JavaScript 没有对属性的引用,这实际上是您尝试在那里使用的。

相反,您可以给自己一个方法,该方法将遍历对象并检索或分配其中的属性。这是 ES5 及更早版本中的快速而肮脏的:

function accessPath(obj, path, value) {
    var o = obj;
    var i = 0;
    var last = path.length - 1;
    while (i < last) {
       o = o[path[i]];
       ++i;
    }
    if (arguments.length < 3) {
        // Getting
        return o[path[last]];
    } else {
        // Setting
        return o[path[last]] = value;
    }
}

活生生的例子:

function accessPath(obj, path, value) {
    var o = obj;
    var i = 0;
    var last = path.length - 1;
    while (i < last) {
       o = o[path[i]];
       ++i;
    }
    if (arguments.length < 3) {
        // Getting
        return o[path[last]];
    } else {
        // Setting
        return o[path[last]] = value;
    }
}

var data = {
   "id":"dfd",
   "properties":{
      "Pri":"2",
      "Brief Description":"asdf",
      "Description":"",
      "tree":{
        "var": "2",
        "rav": "3"
      }
    }   
}

var path = ['properties', 'tree', 'var'];

console.log("Existing: " + accessPath(data, path));
accessPath(data, path, "new value");
console.log("Updated: " + accessPath(data, path));
console.log("Confirm: " + data.properties.tree.var);

在 ES2015+ 中看起来非常相似,除了您可能如何检查是否提供了 value

不漂亮,但相当有效。

实际上,如果我们返回一个带有 getter 和 setter 的对象,我们可以走得更远,这看起来有点像属性引用,即使它实际上不是:

function makeAccessor(obj, path) {
    var o = obj;
    var i = 0;
    var last = path.length - 1;
    var lastName = path[last];
    while (i < last) {
       o = o[path[i]];
       ++i;
    }
    return {
        get value() {
            return o[lastName];
        },
        set value(value) {
            o[lastName] = value;
        }
    };
}

然后,获取访问器:

var accessor = makeAccessor(data, path);

并使用它:

console.log(accessor.value);
accessor.value = "new value";

function makeAccessor(obj, path) {
    var o = obj;
    var i = 0;
    var last = path.length - 1;
    var lastName = path[last];
    while (i < last) {
       o = o[path[i]];
       ++i;
    }
    return {
        get value() {
            return o[lastName];
        },
        set value(value) {
            o[lastName] = value;
        }
    };
}

var data = {
   "id":"dfd",
   "properties":{
      "Pri":"2",
      "Brief Description":"asdf",
      "Description":"",
      "tree":{
        "var": "2",
        "rav": "3"
      }
    }   
}

var path = ['properties', 'tree', 'var'];

var accessor = makeAccessor(data, path);

console.log("Existing: " + accessor.value);
accessor.value = "new value";
console.log("Updated: " + accessor.value);
console.log("Confirm: " + data.properties.tree.var);

【讨论】:

  • 我只用两个参数调用函数时出错,所以我做了一些小调整,效果很好。代码运行良好,谢谢!
  • @Simon2233:这很奇怪,在上面的示例中,它可以很好地处理两个参数。顺便说一句,我为您添加了第二个选项。 :-)
【解决方案2】:

您可以编写小帮手 readwrite 来满足您的需要 - 请注意 data 不会因使用 read 而改变

const read = (o, [k,...ks]) =>
  o ? k === undefined ? o
                      : read (o[k], ks)
    : undefined
    
const write = (o, [k,...ks], v) =>
  o ? ks.length === 0 ? (o[k] = v, null)
                      : write (o[k], ks, v)
    : undefined
    
const data = {
  "id":"dfd",
  "properties":{
    "Pri":"2",
    "Brief Description":"asdf",
    "Description":"",
    "tree":{
      "var": "2",
      "rav": "3"
    }
  }   
}

// read
console.log (read (data, ['properties', 'tree', 'var']))
// => 2
console.log (read (data, ['foo', 'bar', 'barf']))
// => undefined (signals failure)

// write
console.log (write (data, ['properties', 'tree', 'var'], 'new value'))
// => null (signals success)
console.log (write (data, ['foo', 'bar', 'barf'], 'new value')) 
// => undefined (signals failure)

// read updated value
console.log (read (data, ['properties', 'tree', 'var'])) 
// => "new value"

顺便说一下,添加到其他人的 cmets 中,JavaScript Object Notation 是 JSON 所代表的。 Notation 部分使 JSON 不同于“JSO”(JavaScript 对象)。更简单地说,JSON 是 JavaScript 对象的 string 表示。如果不是字符串,你就会知道它不是 JSON。

【讨论】:

  • 最初误读了问题——我不知道我们需要变异数据的能力。
猜你喜欢
  • 2011-01-20
  • 2016-07-23
  • 2015-09-19
  • 2016-02-23
  • 2015-02-21
  • 1970-01-01
  • 2020-03-20
  • 2011-02-05
相关资源
最近更新 更多