In JavaScript, object and array are passed by reference.

Sometimes you may come into trouble if you don’t keep this in mind, especial in
recursion.

Let’s see an example:

First, prepare a JavaScript array to present a tree data:

    var treeData = [{ "name": "root1",
        "kids": [{ "name": "leaf1" }, { "name": "leaf2"}] },
        { "name": "root2"}];

The expected html structure is:

    <ul>
        <li>root1
            <ul>
                <li>leaf1</li>
                <li>leaf2</li>
            </ul>
        </li>
        <li>root2</li>
    </ul>

Our JavaScript code:

    function resolveTree(rootNode, kids) {
        var ulNode = $("<ul />").appendTo(rootNode);
        $.each(kids, function(i, item) {
            var liNode = $("<li />").html(item.name).appendTo(ulNode);
            if (item.kids) {
                resolveTree(liNode, item.kids);
            }
        });
    } 

    resolveTree($("#tree"), treeData);

Next, we want to store the tree node’s path.

For example, leaf1 - [root1, leaf1], leaf2 - [root1, leaf2], root2 - [root2]

We modifiy the resolveTree function:

    function resolveTree(rootNode, kids, path) {
        var ulNode = $("<ul />").appendTo(rootNode);
        $.each(kids, function(i, item) {
            var liNode = $("<li />").html(item.name).appendTo(ulNode);
            path.push(item.name);
            liNode.data("path", path).click(function(event) {
                event.stopPropagation();
                alert($(this).data("path"));
            });
            if (item.kids) {
                resolveTree(liNode, item.kids, path);
            }
            path.pop();
        });
    }
    resolveTree($("#tree"), treeData, []);

The logic must be right, but the result is suprising.

No matter which node i click, the alert box contains an empty string.

What’s the matter?

oh… the array is passed by reference….

The variable path in the code - liNode.data(”path”, path) - is a reference. Then
we want a clone of the array.

There are many method to create a array clone.

    // Method 1
    var newArray = [];
    for (var i = 0; i < oldArray.length; i++) {
        newArray.push(oldArray[i]);
    } 

    // Method 2
    var newArray = oldArray.slice(0); 

    // Method 3
    var newArray = [].concat(oldArray);

The final solution:

    $(function() { 

        var treeData = [{ "name": "root1", "kids": [{ "name": "leaf1" }, { "name": "leaf2"}] }, { "name": "root2"}]; 

        function resolveTree(rootNode, kids, path) {
            var ulNode = $("<ul />").appendTo(rootNode);
            $.each(kids, function(i, item) {
                var liNode = $("<li />").html(item.name).appendTo(ulNode);
                path.push(item.name);
                liNode.data("path", [].concat(path)).click(function(event) {
                    event.stopPropagation();
                    alert($(this).data("path"));
                });
                if (item.kids) {
                    resolveTree(liNode, item.kids, path);
                }
                path.pop();
            });
        } 

        resolveTree($("#tree"), treeData, []);
    });

相关文章: