第 177 题:var、let、const 有什么区别?
var 声明的范围是函数作用域,let 和 const 声明的范围是块作用域,var 声明的变量会被提升到函数作用域的顶部,let 和 const 声明的变量不存在提升,且具有暂时性死区特征,var 允许在同一个作用域中重复声明同一个变量,let 和 const 不允许。
在全局作用域中使用 var 声明的变量会成为 window 对象的属性,let 和 const 声明的变量则不会。
const 的行为与 let 基本相同,唯一 一个重要的区别是,使用 const 声明的变量必须进行初始化,且不能被修改。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
补充一条 "循环绑定"
引言
本文主要介绍
var
、let
、const
关键字的含义,并从四个方面对比
var
、let
、const
声明的变量差异var
在 ES6 之前我们都是通过
var
关键字定义 JavaScript 变量。ES6 才新增了let
和const
关键字在全局作用域下使用
var
声明一个变量,默认它是挂载在顶层对象window
对象下(Node 是global
)用
var
声明的变量的作用域是它当前的执行上下文,可以是函数也可以是全局如果在
foo
没有声明x
,而是赋值,则赋值的是foo
外层作用域下的x
如果赋值给未声明的变量,该变量会被隐式地创建为全局变量(它将成为顶层对象的属性)
var 缺陷一:所有未声明直接赋值的变量都会自动挂在顶层对象下,造成全局环境变量不可控、混乱
变量提升(hoisted)
使用
var
声明的变量存在变量提升的情况注意,提升仅仅是变量声明,不会影响其值的初始化,可以与隐式的理解为:
作用域规则
var
声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问,包含它的代码块对此没有什么影响,所以多次声明同一个变量并不会报错:这种作用域规则可能会引发一些错误
这里很容易看出一些问题,里层的
for
循环会覆盖变量i
,因为所有i
都引用相同的函数作用域内的变量。 有经验的开发者们很清楚,这些问题可能在代码审查时漏掉,引发无穷的麻烦。var 缺陷二:允许多次声明同一变量而不报错,造成代码不容易维护
捕获变量怪异之处
i
是全局变量,全局只有一个变量i
,for
循环结束时,i=10
,所以a[6]()
也为 10 ,并且a
的所有元素里面的i
都为 10而我们期望的是
a[6]()
输出 6,所以我们有了下面的块级作用域let
let
与var
的写法一致,不同的是它使用的是块作用域块作用域变量在包含它们的块或
for
循环之外是不能访问的所以:
同时,
let
解决了var
的两个缺陷:使用 let 在全局作用域下声明的变量也不是顶层对象的属性
那它在哪里喃?
通过上图也可以看到,在全局作用域中,用 let 和 const 声明的全局变量没有在全局对象中,只是一个块级作用域(Script)中
不允许同一块中重复声明
如果在不同块中是可以声明的
这种在一个嵌套作用域中声明同一个变量名称的行为称做 屏蔽 ,它可以完美解决上面的
sumArr
问题:此时将得到正确的结果,因为内层循环的
i
可以屏蔽掉外层循环的i
通常来讲应该避免使用屏蔽,因为我们需要写出清晰的代码。 同时也有些场景适合利用它,你需要好好打算一下
暂时性死区(TDZ)
指
let
声明的变量在被声明之前不能被访问如果你在块中声明
let
,它会报以下错误:即,在块级作用域下报错内容是未初始化,那
let
在块级作用域下有没有被提升喃?TC39 的成员 Rick Waldron 在 hoisting-vs-tdz.md 中这么说:
翻译:
即,通过
let
、const
变量始终“存在”于它们的作用域里,但不能在let
、const
语句之前访问它们,所以不能称为变量提升,只能称为暂时性死区const
const
声明一个只读的常量。一旦声明,常量的值就不能改变。因此,
const
声明的变量不得改变值,这意味着,const
一旦声明变量,就必须立即初始化,不能留到以后赋值。注意,这里
const
保证的不是变量的值不得改动,而是变量指向的那个内存地址不得改动,如果是基本类型的话,变量的值就保存在那个内存地址上,也就是常亮,如果是引用类型,它内部的值是可以变更的其它
const
与let
相同,例如:这里不再赘述
var vs let vs const
var
、let
、const
的不同主要有以下几个方面:作用域规则
let/const
声明的变量属于块作用域,只能在其块或子块中可用。而var
声明的变量的作用域是是全局或者整个封闭函数重复声明/重复赋值
var
可以重复声明和重复赋值let
仅允许重复赋值,但不能重复声明const
既不可以重复赋值,但不能重复声明变量提升(hoisted)
var
声明的变量存在变量提升,即可以在变量声明前访问变量,值为undefined
let
和const
不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错ReferenceError
var:
let:
const:
暂时死区(TDZ)
var
不存在暂时性死区,let
和const
存在暂时性死区,只有变量声明后,才能被访问或使用编程风格
ES6 提出了两个新的声明变量的命令:
let
和const
。其中,let
完全可以取代var
,因为两者语义相同,而且let
没有副作用。所以,我们在开发中建议使用let
、const
,不使用var
参考
原文
1.作用域不同:
var没有块级作用域,let和const有块级作用域
用var声明变量:
运行结果:
循环内i的值:0
循环内i的值:1
循环内i的值:2
循环外i的值:3
用let声明变量:
运行结果:
循环内i的值:0
循环内i的值:1
循环内i的值:2
Uncaught ReferenceError: i is not defined
2.暂时性死区:
只要块级作用域有let、const,他们所声明的变量就绑定这个区域,不受外部影响
运行结果:10
运行结果:Uncaught ReferenceError: Cannot access 'a' before initialization
运行结果:Uncaught ReferenceError: Cannot access 'a' before initialization
3.变量提升:
var声明的变量存在变量提升,let、const不存在变量提升
运行结果:undefined
运行结果:Uncaught ReferenceError: Cannot access 'a' before initialization
4.重复声明
var声明的可以重复声明, let const声明的不可以重复声明
运行结果:20
运行结果:Uncaught SyntaxError: Identifier 'a' has already been declared
5.变量能否被修改
var、let声明的变量可以被修改,const声明的常量不可修改
运行结果:20
运行结果:Uncaught TypeError: Assignment to constant variable
var和let/const的区别
const:
let/const
let 一般用来声明变量
const 声明常量 函数