Ecma262: referencing a const or let variable with this keyword is undefined

Created on 6 Jan 2020  Â·  3Comments  Â·  Source: tc39/ecma262

Description:
I'm not sure if this is an intended feature.
When x is called with this keyword, it gives you an undefined.
I've tried to find the reason for this in ecma-interantional.org but don't know where I could find it.
Could someone provide me a link I can convince myself for why this isn't a bug?

Output:

const x = 1;

console.log(this.x); // undefined
question

Most helpful comment

Could someone provide me a link I can convince myself for why this isn't a bug?

It might help to reframe the question mentally if you’re still trying to see where this does/doesn’t occur. Rather than trying to figure out why it doesn’t happen here, you may have an easier time picking through the spec to figure out why it _does_ happen under specific conditions involving var and function declared bindings in scripts or undeclared bindings in sloppy mode scripts.

(That is, binding declarations leading to global-this property setting or with-statement property setting are the special case. Bindings declared with let, const, and class are purely lexical afaik, so I don’t think you’ll find any steps that ‘stop’ them from setting properties; rather, you’ll find steps that cause specific other cases to set properties for historical reasons.)

Unfortunately I don’t think there’s a single key part of the spec one can point to that explains all this in depth. The behaviors arise from a number of algorithms working together. Some key bits to look at:

  1. The Reference specification type
  2. The related PutValue operation (esp. step 5, where a sloppy unresolvable reference can obtain the global this as the value to which a property gets assigned)
  3. The GetIdentifierReference operation, which is recursive and can bottom out with an unresolvable reference
  4. The runtime semantics (eval rules) of VariableDeclaration : BindingIdentifier Initializer[opt], which use GetIdentifierReference indirectly through ResolveBinding and end with a PutValue call.
  5. The Global Environmental Record spec type and the associated CreateGlobalVarBinding and GlobalDeclarationInstantiation operations.

TBH it’s a bit confusing (and a note in the second-to-last item’s linked op seems to reference a non-existent sixth step...), so I’m not sure I’ve nailed the right/best spots to look at, but hopefully it gives you a handhold for further investigation.

All 3 comments

This isn't a bug because variables aren't the same as properties (except when you're in the global scope of a Script).

Could someone provide me a link I can convince myself for why this isn't a bug?

It might help to reframe the question mentally if you’re still trying to see where this does/doesn’t occur. Rather than trying to figure out why it doesn’t happen here, you may have an easier time picking through the spec to figure out why it _does_ happen under specific conditions involving var and function declared bindings in scripts or undeclared bindings in sloppy mode scripts.

(That is, binding declarations leading to global-this property setting or with-statement property setting are the special case. Bindings declared with let, const, and class are purely lexical afaik, so I don’t think you’ll find any steps that ‘stop’ them from setting properties; rather, you’ll find steps that cause specific other cases to set properties for historical reasons.)

Unfortunately I don’t think there’s a single key part of the spec one can point to that explains all this in depth. The behaviors arise from a number of algorithms working together. Some key bits to look at:

  1. The Reference specification type
  2. The related PutValue operation (esp. step 5, where a sloppy unresolvable reference can obtain the global this as the value to which a property gets assigned)
  3. The GetIdentifierReference operation, which is recursive and can bottom out with an unresolvable reference
  4. The runtime semantics (eval rules) of VariableDeclaration : BindingIdentifier Initializer[opt], which use GetIdentifierReference indirectly through ResolveBinding and end with a PutValue call.
  5. The Global Environmental Record spec type and the associated CreateGlobalVarBinding and GlobalDeclarationInstantiation operations.

TBH it’s a bit confusing (and a note in the second-to-last item’s linked op seems to reference a non-existent sixth step...), so I’m not sure I’ve nailed the right/best spots to look at, but hopefully it gives you a handhold for further investigation.

a note in the second-to-last item’s linked op seems to reference a non-existent sixth step

Interesting, looks like the note was correct in ES2018 but became invalid in ES2019. And it's not alone. Will create a PR to fix, but this makes referring to step numbers seem like a really dangerous practice...

Was this page helpful?
0 / 5 - 0 ratings