2

Im having trouble understanding the difference between these two blocks of code and why one works vs the other. I saw these code snippets in a talk going over the Temporal Dead Zone in JS, but was having a hard time understanding this particular case with default parameters.

Throws a ReferenceError

// sample1.js
const a = 2;
function square(a = a) {
  return a * a;
}
// Does not work!
square();

Works

// sample2.js
const init = 2;
function square(a = init) {
  return a * a;
}
// Works!
square(); // => 4
johnborges
  • 2,422
  • 20
  • 33

3 Answers3

1

Those variables are in the 'inner scope' - even the ..(a=a){...}.

the vars in the inner scope will overwrite (variable scope/shadowing) variables with the same name in the 'outer scope'

so when you try and assign 'a' to 'a' - the inner scope 'a' is overwriting what the variable is in the outer scope and it thinks you're trying to assign something that is in the process of being defined (a = a).

Seems a little silly - as the intention of what you're trying to do is clear, but that's the way it works.

Kyle
  • 1,463
  • 1
  • 12
  • 18
  • 1. It's not called *overwriting* but *shadowing*. Overwriting is when you write to the *same* variable again `a = 3`. Shadowing is when you create a new variable in a nested scope that has the same name as an outer scope variable. 2. "*he intention of what you're trying to do is clear, but that's the way it works*" actually, the intention is not clear at all. Precisely because of the shadowing. It makes as much sense as having `function square(a) { a = a }`. There is no way to determine that the last `a` should be looked up in the outer scope, nor does this functionality even exist. – VLAZ Oct 07 '19 at 19:46
  • ...yes, from the program's pov yes - but if you simply look at the OP example I can understand the confusion because the intention is clear - he wants the var 'a' set the inner var 'a'. I found the intention clear in that sense. – Kyle Oct 07 '19 at 19:53
  • OK, then what about `function square (a) {return a * a}`? With an `a = 2` in the outer scope, when calling `square(3)` what should the result be? `4`. `6` or `9`? After all, each of the two `a` variables in the expression could come from the outer scope... so you could calculate `2 * 2` or `2 * 3` or `3 * 2` or `3 * 3`. Unless we agree that they will be the same one, in which case is it the outer or inner `a` that's referenced? And if it's the inner, then why would it be "clear` that `a = a` would reference two completely different bindings? You can *guess* what OP means but it's not "clear". – VLAZ Oct 07 '19 at 19:58
  • I hear you, but the OP didn't do square(a){return a*a} . It has const a = 2; then on the next line, function square(a=a){...} they are trying to assign that var to the inner one. I personally think it's "clear" what the intention was in the context of this example (which is why the OP is a bit confused, cause at first glance they look fairly strait forward.) – Kyle Oct 07 '19 at 20:33
0

Looks like the JS interpreter thinks that you are trying to assign the parameter a (not yet defined) to itself.

I am not sure if it's possible to refer to the global a in this case, I would just choose another name to avoid misunderstandings and simplify the code. For example, rename the global a to A if it's some global constant.

Alex P.
  • 3,697
  • 9
  • 45
  • 110
0

The reason is the declaration scope that you are trying to set, as you can see this code

const a = 2;
function square(a = a) {
  return a * a;
}
// Does not work!
square();

When you do this, you are telling to JS that argument called a must be assigned to the same a, so the compiler get confused because the declaration for this function block point to the same argument called "a", so when you are trying to assign it to another const name, the compiler can identify that the variable no refer to the same scope for current block.

Juorder Gonzalez
  • 1,642
  • 1
  • 8
  • 10