Default function arguments not using current scope

T.J. Crowder tj.crowder at
Thu Apr 5 09:08:59 UTC 2018

On Thu, Apr 5, 2018 at 9:29 AM, Cyril
Auburtin <cyril.auburtin at> wrote:
> I don't understand:
> ```js
> var z=1; var fn = (z = z) => z; fn()
> // throws ReferenceError: z is not defined
> ```

SpiderMonkey's error message is a bit clearer here:

> ReferenceError: can't access lexical declaration `z' before initialization

Remember that default parameter values have their own scope. In that scope,
they have a TDZ (like `let` and `const` do in a block) until they're
initialized. I believe this is covered in
[FunctionDeclarationInstantiation][1] Step 28. At the point the default
value expression `= z` is evaluated, the `z` parameter has been created as
an uniniitialized binding (by [CreateMutableBinding][2] in 28.f.i.2).
Consequently, it tries to get the value of that uninitialized binding,
which results in a ReferenceError as described in Table 14 under
[Environment Records][3]:

> > GetBindingValue(*N*, *S*) - Returns the value of an already existing
binding from an Environment Record. The String value *N* is the text of the
bound name. *S* is used to identify references originating in strict mode
code or that otherwise require strict mode reference semantics. If *S* is
true and the binding does not exist throw a ReferenceError exception. **If
the binding exists but is uninitialized a ReferenceError is thrown**,
regardless of the value of *S*.

*(My emphasis.)*

E.g., you get that error for the reason you get that same error from:

var z = 42; { console.log(z); let z; }

-- T.J. Crowder

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list