By Benjamin Gruenbaum


2015-02-27 23:27:16 8 Comments

In JavaScript, var declarations create properties on the global object:

var x = 15;
console.log(window.x); // logs 15 in browser
console.log(global.x); // logs 15 in Node.js

ES6 introduces lexical scoping with let declarations that have block scope.

let x = 15;
{
   let x = 14;
}
console.log(x); // logs 15;

However, do these declarations create properties on the global object?

let x = 15;
// what is this supposed to log in the browser according to ES6?
console.log(window.x); // 15 in Firefox
console.log(global.x); // undefined in Node.js with flag

5 comments

@Flimm 2019-01-09 15:03:30

Both let and var variables, if declared at the top-level of a script, are accessible outside of the script file. However, only var variables get assigned to the window object. Have a look at this code snippet as proof:

<script>
  var namedWithVar = "with var";
  let namedWithLet = "with let";
</script>

<script>
  console.log("Accessed directly:");
  console.log(namedWithVar);        // prints: with var
  console.log(namedWithLet);        // prints: with let
  console.log("");

  console.log("Accessed through window:");
  console.log(window.namedWithVar); // prints: with var
  console.log(window.namedWithLet); // prints: undefined
</script>

@S. Mayol 2018-12-05 15:13:41

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

At the top level of programs and functions, let, unlike var, does not create a property on the global object. For example:

   var x = 'global';
   let y = 'global';
   console.log(this.x); // "global"
   console.log(this.y); // undefined

The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global. If you re-declare a JavaScript variable, it will not lose its value. For example:

var x = 1;

if (x === 1) {
  var x = 2;

  console.log(x);
  // output: 2
}

console.log(x);
// output: 2

Note: that unlike C, C++, and Java, JavaScript does not have block-level scope when you declare a variable using var.

As we mentioned before let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. For example:

let x = 1;

if (x === 1) {
  let x = 2;

  console.log(x);
  // output: 2
}

console.log(x);
// output: 1

Here I recommend you to read about Variable Scope

@daGo 2018-12-04 08:33:21

Variables declared via let keyword do not create accessible properties on a global object (window for a browser). Actually, Firefox fixed its behavior: let v = 42; 'v' in window // false

@Felix Kling 2015-02-27 23:45:22

Do let statements create properties on the global object?

According to the spec, no:

A global environment record is logically a single record but it is specified as a composite encapsulating an object environment record and a declarative environment record. The object environment record has as its base object the global object of the associated Realm. This global object is the value returned by the global environment record’s GetThisBinding concrete method. The object environment record component of a global environment record contains the bindings for all built-in globals (clause 18) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the declarative environment record component of the global environment record.

Some more explanation:

  • A declarative environment record stores the bindings in an internal data structure. It's impossible to get a hold of that data structure in any way (think about function scope).

  • An object environment record uses an actual JS object as data structure. Every property of the object becomes a binding and vice versa. The global environment has an object environment object whose "binding object" is the global object. Another example is with.

Now, as the cited part states, only FunctionDeclarations, GeneratorDeclarations, and VariableStatements create bindings in the global environment's object environment record. I.e. only this bindings become properties of the global object.

All other declarations (e.g. const and let) are stored in the global environment's declarative environment record, which is not based on the global object.

@Ben 2015-02-28 00:03:54

But 8.1.1.1 (people.mozilla.org/~jorendorff/…) indicates that let and var create environment records of the same type (i.e. they both create declarative environment records), suggesting that let and var positions on the global object might correspond. I suppose, the global case might be special, however.

@Felix Kling 2015-02-28 00:06:05

let and var don't create records. let and var bindings are "stored" in environment records. And there are different types of environment records: declarative (what you linked to), object, function, module and global, where declarative and object records are the two primary types (and all others are derivates).

@Ben 2015-02-28 00:08:29

Please can you clarify the purpose of your making the distinction. If I declare a variable in the global scope, an environment record is created (and the variable is stored within it like you say). So we are both "correct" no? Are you saying the type of environment record used depends on whether we are in the global scope or not?

@Ben 2015-02-28 00:12:22

Felix, can you confirm that VariableStatement (mentioned in your quote) means specifically function-scoped declaration, or does it include let too? I presume the former.

@Felix Kling 2015-02-28 00:13:43

Here is the definition of VariableStatement: people.mozilla.org/~jorendorff/…. It has nothing to do with functions, it only describes the var.... syntax.

@Ben 2015-02-28 00:14:24

OK, based on this discussion I have to agree. +1

@Ben 2015-02-28 00:15:03

...It does have something to do with functions in as much as var is function-scoped. Nothing more.

@Felix Kling 2015-02-28 00:16:46

@BenAston: I can have var statements outside of functions though (global scope, module scope), so that statement is not 100% correct.

@Felix Kling 2015-02-28 00:18:03

To clarify some things: The big difference between a declarative record and an object record is that a declarative record uses an internal data structure to store the bindings. An object record uses an actual JS object as "storage". In ES5, the global environment was defined as object record (es5.github.io/#x10.2.3), and that's why all variable declarations in global scope become properties of the global object. In ES6 though, the global environment consist of two different environment record types, and only var declarations are stored in the object record, let declarations are not.

@Felix Kling 2015-02-28 00:19:47

(as per the statement I quoted).

@Benjamin Gruenbaum 2015-02-28 01:05:46

Spot on as usual - thanks Felix. You might want to make this answer more approachable to people who are less acquainted with the terminology but it's good as it is.

@Felix Kling 2015-02-28 01:10:37

@Benjamin: I tried with the additional explanation. I might add more later... Thanks for asking interesting questions :)

@Nithin Chandran 2019-06-13 08:01:18

How will i mark global variables declared with let for garbage collection from another script file?

@Felix Kling 2019-06-13 08:09:09

@NithinChandran: If you can always reference any global variable by just its name. E.g. foo = null.

@Nithin Chandran 2019-06-13 08:15:05

@FelixKling but in my case the global variable(using let) is declared in one script file and making it null from another script file. It is showing that the variable is not defined while trying to assign null

@Felix Kling 2019-06-13 08:22:49

@NithinChandran All scripts share the same global scope. If you get an error that means that either variable doesn’t exist yet, or it hasn’t been initialized yet or it is actually not global.

@Nithin Chandran 2019-06-13 12:03:33

@FelixKling but it is perfectly working when declared using var

@Felix Kling 2019-06-13 18:12:13

@NithinChandran: then you are likely trying to assign null to the variable before it was actually initialized. E.g function clear() { foo = null;}; clear(); var foo = 43; works but changing var to let will throw.

@Tracker1 2015-02-27 23:40:24

Per the specification:

"let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment."

This means that you should be able to access the variable inside the execution scope, but not outside. This expands the execution scope beyond the classic JS closure structure of function-only or global.

Defining a let variable globally leaves this open to interpretation, as you see in Firefox it binds a global variable where as V8/iojs does not.

It's worth mentioning that console.log(typeof x) will returl number in iojs. In practice you should not define variables outside of modules, or functions as much as possible... especially with const and let

@Felix Kling 2015-02-28 06:17:16

"Defining a let variable globally leaves this open to interpretation" As you can see from my answer, it does not. What you say is true, we really do have more things that create scope (modules as well), however, that alone does not answer the posed question.

@ecc521 2019-07-07 21:17:47

Firefox appears to have changed it's behavior to be in-line with V8, no longer binding let and const declarations to the global scope.

Related Questions

Sponsored Content

27 Answered Questions

[SOLVED] Iterate through object properties

47 Answered Questions

59 Answered Questions

[SOLVED] How can I merge properties of two JavaScript objects dynamically?

52 Answered Questions

[SOLVED] Create GUID / UUID in JavaScript?

  • 2008-09-19 20:01:00
  • Jason Cohen
  • 1621242 View
  • 3855 Score
  • 52 Answer
  • Tags:   javascript guid uuid

42 Answered Questions

[SOLVED] Detecting an undefined object property

64 Answered Questions

[SOLVED] How do I correctly clone a JavaScript object?

41 Answered Questions

[SOLVED] How do I remove a property from a JavaScript object?

33 Answered Questions

[SOLVED] What's the difference between using "let" and "var"?

69 Answered Questions

[SOLVED] What is the most efficient way to deep clone an object in JavaScript?

41 Answered Questions

[SOLVED] Sort array of objects by string property value

Sponsored Content