Search code examples
javascriptalgorithmglobal-variables

Have a issue with the const , let , var and reference


I am doing some JavaScript coding practice, and I wanna copy the Graph

/**
 * // Definition for a Node.
 * function Node(val, neighbors) {
 *    this.val = val === undefined ? 0 : val;
 *    this.neighbors = neighbors === undefined ? [] : neighbors;
 * };
 */

/**
 * @param {Node} node
 * @return {Node}
 */
var cloneGraph = function(node) {
    
    visited = {};
    return recursion(node);
    
    function recursion(node){
        
        if (!node) return null;
        if (visited[node.val]) return visited[node.val];
        
        // clone node and clone edge
        // **I forgot the let, var, const variable declaration here**
        root = new Node(node.val);
        visited[root.val] = root;
        
        if (!node.neighbors) return root;
        for (let i = 0; i < node.neighbors.length; i++) {
            root.neighbors.push(recursion(node.neighbors[i]));
        }
        return root;
    }
};

Here is my code. I forgot to add the variable declaration const, let, var when initialize the new Node. However, seems like the reference is not correct here.

Error : You must return the copy of the given node as a reference to the cloned graph..

Can any one help me understand, why const the var declaration matters here ? For this coding, var, let, const can pass, however, var says to be global, const and let seems like to be block level right ? Thanks.

However, when use d and c blow, we can get the same output as object.

    d = new Node(node.val)
    console.log(d)
    
    const c = new Node(node.val)
    console.log(c)

Solution

  • Because root has been declare as global variable and be changed in every recursive loop, in this line: root.neighbors.push(recursion(node.neighbors[i])); root will not be the current node that in current loop, but the last reference it has been assigned to.

    Let demonstrate it by an simple graph:

    const oldGraph = [{
      val: 1,
      neighbors: [{
        val: 2
      }, {
        val: 3
      }]
    }];
    

    So run cloneGraph(oldGraph[0]), after value 2 done return after check !node.neighbors, recursion back to the line root.neighbors.push(recursion(node.neighbors[i]));. Now root is the node 2 because it has been assigned to new node val 2 in the second recursion, not the root as node 1 you expected.

    The variable declaration with var, let, const helps in this case, because they keep the root scope inside current recursion, each iteration will create a new root, not changed any other references.

    Test here:

    function Node(node) {
      this.val = node.val;
      this.neighbors = [];
    }
    
    var cloneGraph = function(node) {
        
        visited = {};
        return recursion(node);
        
        function recursion(node){
            
            if (!node) return null;
            if (visited[node.val]) return visited[node.val];
            
            // clone node and clone edge
            // **I forgot the let, var, const variable declaration here**
            let root = new Node(node);
            visited[root.val] = root;
            
            if (!node.neighbors) return root;
            for (let i = 0; i < node.neighbors.length; i++) {
                root.neighbors.push(recursion(node.neighbors[i]));
            }
            return root;
        }
    };
    
    oldGraph = [{
      val: 1,
      neighbors: [{
        val: 2
      }, {
        val: 3
      }]
    }];
    
    console.log(cloneGraph(oldGraph[0]));