var,let,const的区别

let,var,const

var

在ES5中,顶层对象的属性和全局变量是等价的,用var声明的变量既是全局变量,也是顶层变量

注意:顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象

1
2
var a = 10
console.log(window.a) // 10

var声明具有变量提升

1
2
console.log(a)
var a = 10

在编译后会变成

1
2
3
var a
console.log(a) // undefined
a = 10

var声明的变量可以重复声明,后声明的会覆盖之前声明的

1
2
3
var a = 10
var a = 20
console.log(a) // 20

函数中声明var变量是局部变量,不会影响到全局var声明

1
2
3
4
5
6
7
var a = 10
function toSay () {
var a = 20
console.log(a)
}
toSay() // 20
console.log(a) // 10

如果没有使用var声明,相当于在全局声明一个变量

1
2
3
4
5
function toSay () {
a = 20
}
toSay()
console.log(a) // 20

let

let没有变量提升,而且不会挂载到window下,未使用let变量声明前,该变量不可用(暂时性死区)

1
2
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 10;
1
2
let a = 10;
console.log(window.a) // undefined

let具有块级作用域

1
2
3
4
{ 
let a = 10;
}
console.log(a); // ReferenceError: a is not defined
1
2
3
4
5
6
7
let b = 20
function toSay () {
let b = 30 // 因为let是不能重复声明的,由此可证明存在块级作用域
console.log(b)
}
toSay() // 30
console.log(b) // 20

let在相同作用域下不能重复声明

1
2
let c = 10; 
let c = 20; //Uncaught SyntaxError: Identifier 'c' has already been declared

const

const 声明一个常量,一旦声明就不能更改,也不会挂载到window下面

1
2
const d = 10; 
d = 5; //Uncaught TypeError: Assignment to constant variable.

const必须得初始化,初始化之后不能更改

1
const d; // Uncaught SyntaxError: Missing initializer in const declaration
1
2
const d; // Uncaught SyntaxError: Missing initializer in const declaration
d = 10;

const 值不能更改实际指的是不能修改变量保存的指针地址,但是指针指向的数据是可以修改的

1
2
3
4
5
6
7
8
9
10
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

总结

  • var具有变量提升,let,const仅提升声明,形成暂时性死区

  • const初始化必须赋值,letvar仅提升创建操作

  • letconst有块级作用域,var没有

  • var可以重新声明,letconst不可以,let可以在不同作用域下重新声明

  • letvar可以改变值,const不行

  • var会挂载到window下,letconst不会

image.png

最终总结

1.变量提升

var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let和const不存在变量提升(这个说法起始不太严谨,声明的变量有提升,只是初始化没有提升),即它们所声明的变量一定要在声明后使用,否则报错

2.块级作用域

var不存在块级作用域
let和const存在块级作用域

3.重复声明

var允许重复声明变量
let和const在同一作用域不允许重复声明变量

4.修改声明的变量

var和let可以
const声明一个只读的常量。一旦声明,常量的值就不能改变,但对于对象和数据这种引用类型,内存地址不能修改,可以修改里面的值。

变量提升的原理

事实上,JS也是有编译阶段的,它和传统语言的区别在于,JS不会早早地把编译工作做完,而是一边编译一边执行。简单来说,所有的JS代码片段在执行之前都会被编译,只是这个编译的过程非常短暂(可能就只有几微妙、或者更短的时间),紧接着这段代码就会被执行。

JS 和其他语言一样,都要经历编译和执行阶段。正是在这个短暂的编译阶段里,JS 引擎会搜集所有的变量声明,并且提前让声明生效。至于剩下的语句,则需要等到执行阶段、等到执行到具体的某一句的时候才会生效。这就是变量提升背后的机制。

暂时性死区

1
2
3
4
5
6
var me = 'icon';

{
me = 'lee';
let me;
}

错误观点:控制台什么也不输出(理由:全局作用域有一个 me 变量。代码块第一行这个 me,按照作用域规则,引用父级作用域里的 me)

image-20230403133600737

这是因为 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


var,let,const的区别
http://example.com/2023/03/30/07.前端小课堂/02.var,let,const的区别/
作者
Deng ErPu
发布于
2023年3月30日
许可协议