Search code examples
javascriptconsole.logarrow-functionsiifehoisting

How is the arrow function(which is an argument), accepting the value of x as 1 and returning it?


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

This is the code snippet. The output here is (3) [2, 1, 1] How is the third output 1 and not 2?

Also, if I run this code on Scratch JS, it prints (3) [2, 1, 2]

Why is the output different here?

I tried passing a second argument in the IIFE function as in:

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

but this throws an error

Output is (3) [2, 1, 1] in chrome console, but (3) [2, 1, 2] in Scratch JS


Solution

  • How is the third output 1 and not 2? [...] Why is the output different here?

    If the code is run as written, then the default parameter is evaluated before entering the function. So the x in f = () => x is referring to the first parameter of the function, not the var x defined inside of it. And since 1 was passed in to the IIFE, 1 is the value used. Why is the output different here? It appears that scratchJS is transpiling to an older version of javascript. This turns the code into something like this:

     console.log(function (x) {
        var f = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
          return x;
        };
        var x;
        var y = x;
        x = 2;
        return [x, y, f()];
      }(1));
    

    Now the default value is handled by code inside the function body. Because of hoisting, var x is the variable that's referred to when doing return x, not the x in the argument list. By the time f is called, that local variable has been set to 2, so 2 is logged.