1

Why does the first console.log() print undefined values but second one has transformed values? I know it has to do something with function scope but not getting it

var array = [1,2,3,4,5,7];


function incrementByOne(arr) {
  arr = arr.map(function(value, index, array){
    arr[index] = arr[index] +1;
  
  
  });
  console.log(arr);
}



incrementByOne(array);

console.log(array);

// [undefined, undefined, undefined, undefined, undefined, undefined]

// [2, 3, 4, 5, 6, 8]

also i notice that the first console.log() knows how many times to iterate but what happens to the value...

js bin link

Dij
  • 9,761
  • 4
  • 18
  • 35

4 Answers4

2

you need to return the incremented value from the function inside map. use return arr[index] +1 Also you need to return the new array formed using map and stored in arr now.

var array = [1,2,3,4,5,7];


function incrementByOne(arr) { //contains array reference
  arr = arr.map(function(value, index, array){
    return value +1;
  });
  //now arr contains a new array and doesn't refer to passed array anymore.
  console.log(arr);
  return arr;
}


array = incrementByOne(array);

console.log(array);

// [undefined, undefined, undefined, undefined, undefined, undefined]

// [2, 3, 4, 5, 6, 8]

if you don't want to return, you can use forEach(), as in that case arr will refer to passed array throughout. The difference is because map returns a new array.

var array = [1,2,3,4,5,7];


function incrementByOne(arr) { //contains array reference
  arr.forEach(function(value, index){
    arr[index] = value +1;
  });
  //arr still refers to the passed array.
  console.log(arr);
}


incrementByOne(array);

console.log(array);

// [undefined, undefined, undefined, undefined, undefined, undefined]

// [2, 3, 4, 5, 6, 8]
Dij
  • 9,761
  • 4
  • 18
  • 35
  • Yeah but that doesn't answer the question about the scoping... wouldn't you expect the output to be consistent inside and outside the scope of the function in which the map is applied? – kpie Aug 05 '17 at 03:30
  • ok actually now the 2nd console.log doesnt have the transformed value, what i did that works is: return arr[index] = arr[index] +1; – Serge Urakhchin Aug 05 '17 at 03:31
  • Because incrementByOne(arr) needs to `return(arr)` and when you call it you need to assign the result to array, `array = incrementByOne(Array)` – kpie Aug 05 '17 at 03:34
  • `return arr[index] +1` - real programmers would `return value + 1` :p – Jaromanda X Aug 05 '17 at 03:42
0

A couple of things going on here:

  1. The callback you pass into the .map function should return a value with the return keyword. If you don't return a value from the callback, the default return value is undefined. That's why the 'arr' array you define in incrementByOne only has undefined values inside of it when you log it with your first console.log. I think what you're really trying to do is simply return value + 1 inside of the callback.

  2. You're making a classic passed-by-value passed-by-reference error here; it's a mistake everyone makes when they're first learning JS. I'd recommend checking out posts like this one. In short, inside of your .map callback you are mutating the array that you passed into incrementByOne, which is the same array you log out with the second console.log; that's why the values appear to have been incremented correctly.

PeterMader
  • 6,987
  • 1
  • 21
  • 31
Sean
  • 76
  • 3
0

var array = [1,2,3,4,5,7];


function incrementByOne(arr) {
  arr = arr.map(v => v + 1);
  console.log(arr);
}



incrementByOne(array);

console.log(array);

// [undefined, undefined, undefined, undefined, undefined, undefined]

// [2, 3, 4, 5, 6, 8]
tibetty
  • 563
  • 2
  • 10
0

Well, all the above answers are correct but they miss the most important point here. There is a concept in JavaScript called call by sharing.

Consider this code:

var num= 3;
var json = {myValue : '10'};
var json2 = {myValue : '100'};

function callBySharing(a,b,c){
 a = a + 37;
 b = {myValue : 'new value'};
 c.myValue = 'new Value';
}

callBySharing(num,json,json2);

console.log(num);//3 *UNCHANGED*
console.log(json.myValue);//10 *UNCHANGED*
console.log(json2.myValue);//'new Value' *CHANGED*

So what you are doing is same as what is happening in json.myvalue; You are trying to update the whole object and replace it with the new value. So a very simple change in the code with do this for you:

var array = [1,2,3,4,5,7];


function incrementByOne(arr) {
  arr.map(function(value, index, array){
    arr[index] = arr[index] +1;
  
  
  });
  console.log(arr);
}



incrementByOne(array);

console.log(array);

I just replaced the arr= arr.map().... part to just arr.map().....

What this does is, it changes the function to json2.myValue example case.

So what is the difference between the 2: JS lets you update items within the object but not the whole object.By making the above said change in code, you are updating individual values of arr and not replacing the whole object with new values. I learnt this concept from SO only back when I was confused with it. So I am linking the post(Is JavaScript a pass-by-reference or pass-by-value language?)

Hope this helps!

Aman
  • 149
  • 13