【问题标题】:Walk and set value to complex Javascript object步行并为复杂的Javascript对象设置值
【发布时间】:2013-09-13 10:20:45
【问题描述】:

我注意到这篇文章有以下相似之处: Dynamic deep setting for a JavaScript object

但是,上面的帖子是基于 javascript 对象的已知结构和深度,而不是真正动态的。真正的动态意味着您对结构没有任何先验知识,只是一个路径和一个替换它的值。我在 JSFiddle 上创建了一个相当不错的用例:

http://jsfiddle.net/kstubs/nJrLp/1/

function Message(message) {
$('result').insert('<div>' + message + '</div>');
}

var obj = {
"array": [1, 2, 3],
"boolean": true,
"null": null,
"number": 123,
"object": {
    "a": "b",
    "c": "d",
    "e": "f",
    "complex_array1": [{
        "g": "h"
    }, {
        "bingo": "bongo"
    }, {
        "x": {
            "complex_array2": [{
                "h": "i"
            }, {
                "j": "k"
            }, {
                "bingo": "bongo"
            }, {
                "bango": "jango"
            }]
        }
    }]
},
"string": "Hello World"
};

var list = [{
"h": "i"
}, {
"j": "k"
}];

function walk(path,value) {
var a = path.split('.');
var context = obj;

for (i = 0; i < a.size(); i++) {
    context = context[a[i]];
}

}

用例:

  1. 查找 complex_array2
  2. 将其列表更新为新列表(新数组)

新数组是应该替换complex_array2 列表的数组列表。 javascript 函数 walk 就是这样做的,遍历 javascript 对象直到满足路径条件,然后将值设置为传递给 walk 函数的任何值,但是新值不会保留。

我知道为什么它不会粘住,因为当你走过一个数组类型的对象时,你会丢失指向原始对象的指针。因此,挑战在于 walk javascript 对象,并且不丢失原始对象的上下文。

感谢您的帮助。

卡尔..

【问题讨论】:

  • 那么....问题是什么?您真的需要它还是只想挑战 SO 用户?你试过什么?
  • var context = obj, old=obj; ...老[a[i]]="随便"
  • 这可能很有趣——我自己对一个略有不同的问题的答案之一——stackoverflow.com/questions/12163160/…
  • 是的@AurelioDeRosa 确实需要。我有一个复杂的 javascript 对象,它动态绑定到 Web 表单。该对象作为 Json 字符串存储在文本字段中。

标签: javascript


【解决方案1】:

我使用了一个辅助函数来读取复杂的 json 对象。 (http://jsfiddle.net/JBBAJ/)

var object = {
    data: {
        users: [
            {
                firstName: "White"
            },
            {
                firstName: "Black"
            }
        ]
    }
}
var read = function(path, obj) {
    var path = path.split(".");
    var item = path.shift();
    if(item.indexOf("]") == item.length-1) {
        // array
        item = item.split("[");
        var arrayName = item.shift();
        var arrayIndex = parseInt(item.shift().replace("]", ""));
        var arr = obj[arrayName || ""];
        if(arr && arr[arrayIndex]) {
            return read(path.join("."), arr[arrayIndex]);
        } else {
            return null;
        }
    } else {
        // object
        if(obj[item]) {
            if(path.length === 0) {
                return obj[item];
            } else {
                return read(path.join("."), obj[item]);
            }
        } else {
            return null;
        }
    }

}
console.log(read("data.users[0].firstName", object)); // White
console.log(read("data.users[1].firstName", object)); // Black
console.log(read("data.test.users[0]", object)); // null

read 函数接受路径和对象。

【讨论】:

    【解决方案2】:

    只需遍历路径中除最后一个元素之外的所有元素。然后最后一个元素用于循环后的赋值。

    var i = 0;
    
    for (; i < a.size() - 1; i++) {
        context = context[a[i]];
    }
    
    context[a[i]] = value;
    

    从技术上讲,您可以将i 的声明留在for 中。我只是觉得这更清楚。

    http://jsfiddle.net/nJrLp/2/

    【讨论】:

    • 没错!我想出了相同的答案:jsfiddle.net/kstubs/nJrLp/3 基于 Andrew 的言论。
    • 这与此无关,但是您使用i 而不首先使用var 声明它的方式使其成为全局变量。你真的不应该那样做。
    【解决方案3】:

    您的代码在编写时无法正常工作的原因是,您实际上是在更改局部变量指向的对象,而不是更改您引用的对象的属性。

    context = context[a[i]];
    

    context 是一个指向对象的指针,它是一个局部变量。当您分配给它时,您正在分配一个新的指针值,它会丢失对前一个对象的引用。如果要替换它,则必须从其父对象中引用它。假设parent 就是这样一个对象;一旦找到目标对象的键名(假设您已将其放在变量 key 中),您就可以像这样覆盖现有值:

    parent[key] = new_value;
    

    这将取消引用parent,找到以key命名的属性,并将其值(即指针)替换为new_value的内存地址。你目前的工作是这样的:

    var context = parent[key];
    context = new_value;
    

    在这种情况下,您只是更改了局部变量 context 的指针值,而不是 parent[key] 指向的对象。

    【讨论】:

    • 像这样:jsfiddle.net/kstubs/nJrLp/3 看起来这很有效,太棒了。将其插入真正的解决方案,并将报告我可能发现的任何其他问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-09
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多