var,let,const的区别
# let,var,const
# var
在ES5中,顶层对象的属性和全局变量是等价的,用var
声明的变量既是全局变量,也是顶层变量
注意:顶层对象,在浏览器环境指的是window
对象,在 Node
指的是global
对象
var a = 10
console.log(window.a) // 10
2
var声明具有变量提升
console.log(a)
var a = 10
2
在编译后会变成
var a
console.log(a) // undefined
a = 10
2
3
var声明的变量可以重复声明,后声明的会覆盖之前声明的
var a = 10
var a = 20
console.log(a) // 20
2
3
在函数中声明var变量是局部变量,不会影响到全局var声明
var a = 10
function toSay () {
var a = 20
console.log(a)
}
toSay() // 20
console.log(a) // 10
2
3
4
5
6
7
如果没有使用var声明,相当于在全局声明一个变量
function toSay () {
a = 20
}
toSay()
console.log(a) // 20
2
3
4
5
# let
let没有变量提升,而且不会挂载到window下,未使用let变量声明前,该变量不可用(暂时性死区)
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 10;
2
let a = 10;
console.log(window.a) // undefined
2
let具有块级作用域
{
let a = 10;
}
console.log(a); // ReferenceError: a is not defined
2
3
4
let b = 20
function toSay () {
let b = 30 // 因为let是不能重复声明的,由此可证明存在块级作用域
console.log(b)
}
toSay() // 30
console.log(b) // 20
2
3
4
5
6
7
let在相同作用域下不能重复声明
let c = 10;
let c = 20; //Uncaught SyntaxError: Identifier 'c' has already been declared
2
# const
const 声明一个常量,一旦声明就不能更改,也不会挂载到window下面
const d = 10;
d = 5; //Uncaught TypeError: Assignment to constant variable.
2
const必须得初始化,初始化之后不能更改
const d; // Uncaught SyntaxError: Missing initializer in const declaration
const d; // Uncaught SyntaxError: Missing initializer in const declaration
d = 10;
2
const 值不能更改实际指的是不能修改变量保存的指针地址,但是指针指向的数据是可以修改的
const a = {
b: 2
}
a.b = 3
console.log(a.b) // 3
const b = [1,2,3,4]
b[2] = 5
console.log(b) // [1,2,5,4]
// 不能把a指向另一个变量
a = {} // TypeError: "a" is read-only
2
3
4
5
6
7
8
9
10
# 总结
var
具有变量提升,let
,const
仅提升声明,形成暂时性死区const
初始化必须赋值,let
和var
仅提升创建操作let
和const
有块级作用域,var
没有var
可以重新声明,let
和const
不可以,let
可以在不同作用域下重新声明let
和var
可以改变值,const
不行var
会挂载到window
下,let
和const
不会
# 最终总结
# 1.变量提升
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined let和const不存在变量提升(这个说法起始不太严谨,声明的变量有提升,只是初始化没有提升),即它们所声明的变量一定要在声明后使用,否则报错
# 2.块级作用域
var不存在块级作用域 let和const存在块级作用域
# 3.重复声明
var允许重复声明变量 let和const在同一作用域不允许重复声明变量
# 4.修改声明的变量
var和let可以 const声明一个只读的常量。一旦声明,常量的值就不能改变,但对于对象和数据这种引用类型,内存地址不能修改,可以修改里面的值。
# 变量提升的原理
事实上,JS也是有编译阶段的,它和传统语言的区别在于,JS不会早早地把编译工作做完,而是一边编译一边执行。简单来说,所有的JS代码片段在执行之前都会被编译,只是这个编译的过程非常短暂(可能就只有几微妙、或者更短的时间),紧接着这段代码就会被执行。
JS 和其他语言一样,都要经历编译和执行阶段。正是在这个短暂的编译阶段里,JS 引擎会搜集所有的变量声明,并且提前让声明生效。至于剩下的语句,则需要等到执行阶段、等到执行到具体的某一句的时候才会生效。这就是变量提升背后的机制。
# 暂时性死区
var me = 'icon';
{
me = 'lee';
let me;
}
2
3
4
5
6
错误观点:控制台什么也不输出(理由:全局作用域有一个 me 变量。代码块第一行这个 me,按照作用域规则,引用父级作用域里的 me)
这是因为 ES6 中有明确的规定:如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。假如我们尝试在声明前去使用这类变量,就会报错。(暂时性死区)
产生暂时性死区的原因(ES6标准): The variables are created when their containing Lexical Environment is instantiated but may not be accessed inany way until the variable ' s LexicalBinding is evaluated .(这些变量是在实例化包含它们的 Lexical Environment 时创建的,但在评估变量的 LexicalBinding 之前不能以任何方式访问。
let / const 会先被创建出来,但还未绑定值,所以不能用
在代码块内,使用let命令声明变量之前,该变量都是不可用的
# 参考文章
https://juejin.cn/post/6991053348396859428
https://juejin.cn/post/6991018402437398541
https://juejin.cn/post/6968399560162951204