The ES2015 (ES6)
introduced two important JavaScript
keywords: let
and const
.
If there is let
or const
inside a code block, the code block will form a closed scope for the variables declared by these commands from the beginning of the block.
{
let a = 1;
var b = 2;
function s(){return a;}
console.dir(s);
/*
...
[[Scopes]]: Scopes[2]
0: Block {a: 1}
1: Global ...
*/
}
// a cannot be used here, as it is block-scoped
// b can be used here, as it is globally scoped
[[Scopes]]
is an object that saves the function's scope chain and is an internal property of the function that cannot be directly accessed. In [[Scopes]]
, we can see the appearance of a Block
block-level scope. This makes let
especially suitable for use inside for
loops. Before the introduction of the let
keyword in ECMAScript 2015
, there were only function scope and global scope. Functions could nest within function scopes, but there was no true block scope within for
loops, leading to a common closure creation problem.
function counter(){
var arr = [];
for(var i = 0 ; i < 3 ; ++i){
arr[i] = function(){
return i;
}
}
return arr;
}
var coun = counter();
for(var i = 0 ; i < 3 ; ++i){
console.log(coun[i]()); // 3 3 3
}
The output is 3 3 3
instead of the expected 0 1 2
. The reason is that when these three closures are created during the loop, they share the same lexical scope. This scope, due to the existence of an i
declared with var
, has a function scope. By the time the closure function is executed, the loop has already finished, and i
has been assigned the value of 3
, resulting in the printout 3 3 3
. This problem can be solved by using the let
keyword to declare i
and create block-level scope.
function counter(){
var arr = [];
for(let i = 0 ; i < 3 ; ++i){
arr[i] = function(){
return i;
}
}
return arr;
}
var coun = counter();
for(var i = 0 ; i < 3 ; ++i){
console.log(coun[i]()); // 0 1 2
}
Alternatively, the issue can also be resolved by using an anonymous function to create a function scope.
function counter(){
var arr = [];
for(var i = 0 ; i < 3 ; ++i){
(function(i){
arr[i] = function(){
return i;
}
})(i);
}
return arr;
}
var coun = counter();
for(var i = 0 ; i < 3 ; ++i){
console.log(coun[i]()); // 0 1 2
}
Within the same scope, let
and const
can only be declared once, while var
can be declared multiple times.
let a = 1;
let a = 1; //Uncaught SyntaxError: Identifier 'a' has already been declared
const b = 1;
const b = 1; //Uncaught SyntaxError: Identifier 'b' has already been declared
When using let
and const
to create block-level scope, the code block will form a closed scope for the variables declared by these commands from the beginning of the block. Within the code block, using a variable before its declaration will result in an error, known as the temporal dead zone.
{
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a =1;
}
let
and const
have variable hoisting as well. In the ES6
documentation, there is the term var/let hoisting
, indicating that the official documentation explains that let
and var
are the same, both have variable hoisting, but the variable hoisting of let
is different from that of var
.
The "creation" process of `let` is hoisted, but the initialization is not hoisted.
Both the "creation" and "initialization" of `var` are hoisted.
Both the "creation", "initialization", and "assignment" of `function` are hoisted.
A convincing example found on stackoverflow
is as follows:
x = "global";
// function scope:
(function() {
x; // not "global"
var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global"
let/const/… x;
}
In js
, regardless of the declaration form (var
, let
, const
, function
, function*
, class
), hoisting occurs. However, the difference is that the declarations of var
, function
, and function*
are initialized to undefined
during hoisting, so when accessing these variables, no ReferenceError
exception will be thrown. On the other hand, the variables declared with let
, const
, and class
are hoisted without being initialized, and these variables are said to be in the "temporal dead zone", hence accessing them will result in a ReferenceError
exception, making it appear as if they were not hoisted at all.
https://blog.csdn.net/jolab/article/details/82466362
https://www.jianshu.com/p/0f49c88cf169
https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6
When using var
to directly declare variables or methods in the global scope, they will be attached to the window
object, while the variables or methods declared using let
and const
will be saved in the Script
scope.
var a = 1;
let b = 2;
const c = 3;
console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined
let a = 1;
{
let b = 2;
function s(){return a + b;}
console.dir(s);
/*
...
[[Scopes]]: Scopes[3]
0: Block {b: 2}
1: Script {a: 1}
2: Global ...
*/
}
var
and let
can be declared without initializing, whereas const
must be initialized.
var a;
let b;
const c; //Uncaught SyntaxError: Missing initializer in const declaration
const
is used to declare a read-only constant, and once initialized, its value cannot be changed.
const a = 1;
a = 2; // Uncaught TypeError: Assignment to constant variable.
In fact, const
ensures not the immutability of the variable's value, but that the data stored at the memory address pointed to by the variable cannot be changed. For simple types like number
, string
, boolean
, and Symbol
, the value is stored at the memory address pointed to by the variable, making const
of these simple type variables equivalent to constants. For complex types like object
, array
, and function
, the variable points to the memory address where a pointer to the actual data is stored, so const
can only guarantee that the pointer is fixed, and it cannot control whether the data structure pointed to by the pointer changes.
const a = {};
console.log(a); // {}
a.s = function(){}
console.log(a); // {s: ƒ}
https://github.com/WindrunnerMax/EveryDay
ES6 Features https://github.com/WindrunnerMax/EveryDay/blob/master/JavaScript/ES6%E6%96%B0%E7%89%B9%E6%80%A7.md
Js Variable Hoisting https://github.com/WindrunnerMax/EveryDay/blob/master/JavaScript/JS%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87.md