- Can anyone explain why
testVariable
has two different ouputs when using let
. And why there isn't any runtime error when varibles with the same name are defined in window
object?
Object.defineProperty(window, 'testVariable', {
value: 22
})
let testVariable = 12
console.log(window.testVariable) // result: 22
console.log(testVariable) // result: 12
- But when using
var
, the outputs are the same.
Object.defineProperty(window, 'testVariable', {
value: 22
})
var testVariable = 12
console.log(window.testVariable) // result: 12
console.log(testVariable) // result: 12
- Why following code runs correctly
<script>
Object.defineProperty(window, 'a', {
value: 33
})
let a = 13
</script>
<script>
console.log(a) // result: 13
</script>
- But the following throws an error.
<script>
Object.defineProperty(window, 'a', {
value: 33
})
</script>
<script>
let a = 13
console.log(a) // Uncaught SyntaxError: Identifier 'a' has already been declared
</script>
When a variable is declared with
var
on the top level, as soon as the script tag starts, it's assigned as a writable property of the global object:The same is not true for variables declared with
let
- they don't get put onto the global object:When you use
Object.defineProperty
to define a property that's already defined on the object, and you pass avalue
, like withThe prior value that existed on the object gets overwritten. So with your second code, you're defining a writable property named
testVariable
on the global object which then gets overwritten, and bothtestVariable
andwindow.testVariable
evaluate to12
.In contrast, with your first code, top-level variables declared with
let
create a global identifier, but do not get assigned to properties of the global object, soand
are referring to different things.
This one is quite interesting. According to the specification, when the environment prepares to execute a new
<script>
tag, it runsGlobalDeclarationInstantiation
to set things up. It does, among other things:Where
envRec
is the global Environment Record. (An Environment Record, or Lexical Environment, is a record of which variable names in a given scope refer to which values.)With your code, the section of
GlobalDeclarationInstantiation
that is throwing is this section of 5:In your third code, before the first script tag starts, when
GlobalDeclarationInstantiation
runs, the global environment record doesn't have a variable nameda
, so no error is thrown. In contrast, in your fourth code, when the second script tag starts, andGlobalDeclarationInstantiation
runs, a variable nameda
declared withlet
already exists in the global environment record, so theHasLexicalDeclaration
call returnstrue
, and an error is thrown. (Variables declared withlet
create lexical declarations; variables declared withvar
create var declarations.)