-2

I was learning about arrow function in js where I found one question

console.log((function(x, f = () => x) {
  var x;
  var y = x;
  x = 2;
  return [x, y, f()];
})(1));

It's output is 2,1,1 but it should be 1,1,1.

Can anyone explain it?

David
  • 208,112
  • 36
  • 198
  • 279
Deepak _8097
  • 27
  • 1
  • 4
  • 1
    Because, `x = 2;` – Mr. Polywhirl Oct 26 '21 at 12:55
  • 1
    Can you explain why you expect the first element in the result to be `1`? Or what this even has to do with arrow functions at all, since the only difference in the result isn't produced by an arrow function? If the only difference you're seeing from observed vs. expected results is the first value in the response, simplify the code and refactor out anything unrelated to that first value. What do you end up with? – David Oct 26 '21 at 12:56
  • @Mr.Polywhirl f = () => x what does it mean? – Deepak _8097 Oct 26 '21 at 12:56
  • 3
    Are you asking why `console.log([2, 1, 1])` prints `2, 1, 1` instead of `1, 1, 1`? – jabaa Oct 26 '21 at 12:56
  • @David Why the value of y is 1? – Deepak _8097 Oct 26 '21 at 12:57
  • Or instead of `2, 1, 2` since `f()` returns `x` – pilchard Oct 26 '21 at 12:57
  • Because you set y = x before reassigning x – pilchard Oct 26 '21 at 12:58
  • You are confused because the code snippet you shared is using `Variable shadowing` – B Thuy Oct 26 '21 at 12:58
  • @Deepak_8097: Because when you did this: `var y = x;` the value of `x` *at that time* was `1`. – David Oct 26 '21 at 12:58
  • _"Why the value of y is 1?"_ Because `var y = x;` is a copy. Changing `x` won't change `y`. – jabaa Oct 26 '21 at 12:58
  • @jabaa I am confused with f = () => x this syntax? – Deepak _8097 Oct 26 '21 at 12:58
  • How is the third element of the array related to the first element? _"It's output is `2,1,1` but it should be `1,1,1`."_ The only difference between your expected output and the actual output is the first element of the array, the value of `x`. It's unrelated to `f = () => x`. Why do you expect the first element to be `1`? – jabaa Oct 26 '21 at 12:59
  • if you don't pass a second parameter, that parameter is a function returning `x` – pilchard Oct 26 '21 at 12:59
  • Does this help: https://jsfiddle.net/uzL4n3p1/ – jabaa Oct 26 '21 at 13:03

2 Answers2

1

Here is the function re-written to show what is happening.

  1. main takes x = 1
  2. defaultFunction returns the original x = 1
  3. resultFn is a function that gets called inside of main that takes x
  4. y is assigned the x that was passed all the way down (local -scope) 1
  5. x is reassigned to 2
  6. The result is 2, 1, 1

This is an exercise on variable/parameter scope.

const main = (x) => {                      // x = 1
  const defaultFn = () => x;               // x = 1
  const resultFn = (x, f = defaultFn) => { // x = 1
    var x;                                 // x is still 1
    var y = x;                             // y = 1
    x = 2;                                 // x = 2
    return [x, y, f()];                    // x = 2, y = 1, f() -> 1
  };
  return resultFn(x);                      // 2, 1, 1
};

console.log(main(1));
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
  • At least for me this behavior is very confusing. I expected `var x;` to introduce a new, uninitialized variable that shadows the parameter `x`. I was surprised that `y` was set to `1` and not `undefined`. With this question and your answer I learned that `var x;` is a redeclaration and `let x;` causes an error. – jabaa Oct 26 '21 at 13:17
  • 1
    @jabaa see: [Redeclaring a javascript variable](https://stackoverflow.com/questions/6888506/redeclaring-a-javascript-variable) (var specific, ah hoisting) – pilchard Oct 26 '21 at 13:27
  • 1
    @pilchard Yes, I got it after some testing and reading but I was surprised. JavaScript can be confusing. It's great that `var` was replaced with `let` and `const`. – jabaa Oct 26 '21 at 13:28
0

You set x to 2 thus it got returned as 2. Change x to 1. Fixed Code:

console.log((function(x, f = () => x) {
  var x;
  var y = x;
  x = 2;
  return [x, y, f()];
})(1));
MXCDR
  • 21
  • 4
  • What does it mean f = () => x? – Deepak _8097 Oct 26 '21 at 13:03
  • @Deepak_8097 `() => x` defines an [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) and `f = () => x` assigns this function to `f`. – jabaa Oct 26 '21 at 13:05
  • it assigns it *if* no parameter is passed. – pilchard Oct 26 '21 at 13:09
  • This is a tricky [closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) situation. – pilchard Oct 26 '21 at 13:10
  • 1
    @MXCDR _"it assigns x to f"_. No, it doesn't. `x` contains a number. `f` contains a function. – jabaa Oct 26 '21 at 13:14
  • @jabaa Okay it is an arrow function and it is returning the value of x. – Deepak _8097 Oct 26 '21 at 13:20
  • @Deepak_8097 Yes, it's a function that reads the value of a copy of `x` and returns it. It doesn't change any variable. So it's still unclear why you expect `x` to equal `1` after `x = 2;`. – jabaa Oct 26 '21 at 13:23