Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

issue with calling a javascript function twice

I am trying to write a fairly simple Javascript function, and experiencing behavior I don't understand when I iterate the function.

I have distilled the problem down to the following situation. I want to write a function that will take as input an array consisting of arrays of arrays, e.g. A = [[[1]]]. I don't know the standard terminology for this, so I am going to refer to the main array as "level 0", which has elements that are arrays of "level 1". I'll say the level 1 arrays consist of arrays of "level 2". The level 2 arrays consist of integers.

The function does the following, on input A (a level 0 array):

  1. create an empty array L;
  2. for each level 1 array M in A
    • add one to each integer entry in each level 2 array in M;
    • add two copies of M to L
  3. return L.

Here is my code:

function myFunc(A){
  var L = [];
  for(var a=0; a<A.length; a++){
    var M = A[a].slice(0);
    for(var i=0; i<M.length; i++){
      for(var j=0; j<M[i].length; j++){
        M[i][j]++;
      }
    }
    for(var s=0; s<2; s++){
      var N = M.slice(0);
      L.push(N);
    }
  }
  return(L);
}

Now I test it out:

var A = [[[1]]];

A = myFunc(A)

After this, I get A = [[[2]],[[2]]], which is what I expect. However, suppose I iterate it:

var A = [[[1]]];

A = myFunc(A);

A = myFunc(A);

Then I expect to obtain A = [[[3]],[[3]],[[3]],[[3]]], but instead I have A = [[[4]],[[4]],[[4]],[[4]]].

On the other hand if I run myFunc([[[2]],[[2]]]), I do get the expected [[[3]],[[3]],[[3]],[[3]]].

I don't understand where this discrepancy is coming from.

like image 506
Gabe Conant Avatar asked Apr 12 '15 20:04

Gabe Conant


People also ask

Can you call a function multiple times in JavaScript?

In order to run a function multiple times after a fixed amount of time, we are using few functions. setInterval() Method: This method calls a function at specified intervals(in ms). This method will call continuously the function until clearInterval() is run, or the window is closed.

Can you return twice in JavaScript?

You can't, it is only possible once.

How do you keep a function from repeating in JavaScript?

One of the most common ways to create a loop is by using the for statement to create a for loop. A for loop allows us to repeatedly run some code until an expression we specify returns false.

How do you check if function is called twice?

debugger; statement there, and open the JavaScript console. There will be an option in that debugger to see a stack trace. The stack trace will let you see exactly where a function was called from, so you can see if it is being called from two different points.


1 Answers

The problem is the line:

M[i][j]++;

Node keeps this as a reference to your A's slice, and you see it clearly when you do this :

x = [[[1]]];
myFunc(x);
myFunc(x);
console.log(x); // ---> [[[3]]]

For a shallow copy you'd have to use the JSON.parse(JSON.stringify()) trick, and proof that M is the problem; adding this line just after M = A[a].slice(0); solves the issue.

M = JSON.parse(JSON.stringify(M))

Mozilla's documentation about Array.prototype.slice() :

For object references (and not the actual object), slice copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.

Source

That is why, because when you do M[i][j], the array a level deeper is still referenced outside.

like image 170
Tristan Foureur Avatar answered Sep 28 '22 11:09

Tristan Foureur