3.3.2 let 声明

let 和 var 的作用差不多,都是声明 变量 的。但是它们有非常明显的区别:

区别:

let 关键字声明的变量是 块级作用域。
所谓 块级作用域 就是在 { 到 } 内的,以及 for 循环,while 循环,if 语句内,当程序执行完这些 块级作用域 的时候,在该作用域的 定义的 let 变量 会被注销。在块级作用域外是无法 调用的。

var 关键字声明的变量是 函数作用域。
在函数内定义的 var 变量,在函数外无法调用。也会随着函数执行的结束而销毁。在函数内部是可以随意调用的。即使是函数的内部函数依然可以调用。

联系

块级作用域 是 函数作用域 的子集,因此适用于 var 的作用域限制同样适用于 let 。

let 也不允许在同一个 块级作用域 中冗余声明,这样会报错。

var name;
var name;

let age;
let age;	// 报错 SyntaxError,标识符 age 已经声明过了。

当然,JavaScript引擎会记录用于变量声明的标识符 以及所在的的 块级作用域,因此嵌套使用标识符 不会报错,而这是因为同一个块中没有重复声明。

对声明冗余报错不会因为混用 tel 和 var 而受影响。着两个关键字声明的并不是不同类型的变量,它们只是指出变量在相关作用域是如何存在。

var name;
let name;	// SyntaxError

lat age;
let age;	// 报错 SyntaxError,标识符 age 已经声明过了。

1、暂时性死区

let 与 var 的另一个重要区别,就是 let 声明的变量不会再作用域中 被提升。

// name 会被提升
console.log(name);	// undefined 
var name = "matt";

// ger 不会被提升
console.log(age);
let age = 26;	// ReferenceError:age 没有定义

再解析代码的时候,JavaScript引擎会注意出现在 块后面的 let 声明,只不过在此之前不能以任何方式来引用为声明的变量。
在 let 声明之前的执行瞬间被称为 “暂时性死区 ” (temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError 错误。

2、全局声明

与 var 关键字不同,使用 let 在 全局作用域 中声明的变量不会成为 window 对象的属性( var 声明的变量 则会 )。

 var name = "Matt";
 console.log(window.name);	// 会打印 Matt 

let age = 26;						
console.log(window.age);    //   undefined 

不过, let 声明仍然是在全局作用域 中发生的,相应变量会在页面的生命周期内存续。因此,为了避免 SyntaxError ( 语法错误),必须确保同一个页面不会声明同一个变量。

3、条件声明

在 var 声明的变量时,由于声明会被 提升,JavaScript引擎会自动将多余的相同操作符的声明在 作用域顶部合并为一个声明。
因为 let 的作用域是 块级,所以不能检查前面是否已经使用 let 声明过 同名 变量,同名时就不可能在没有声明的情况下声明它。

<script>
	var name = 'Nicholas';
	let age = 26;
</script>

<script>
	// 假设 脚本 不晓得前面是否声明过同名的变量,那就假设它没有声明过。
	var name = 'Matt";	// 这里没有问题,因为可以被作为一个 提升变量来处理,那么就不需要检查之前是否创建过同名的变量名。

	let age = 36;	// 如果 age 以前声明过,那么这里会 报错。
</script>

但是也不要妄想用 try…catch 语句或者 typeof 操作符 来动态生成 未定义的变量,因为 条件块中 let 声明的 作用域仅限于 该条件块内。
为此,对于 let 关键字 声明变量 不能依赖 条件声明模式。

4、for 循环中的 let 声明

在 let 出现之前,for 循环定义的 迭代变量的 作用域 会溢到 循环体 外部:

for ( var i = 0;i < 5 ; i++){
	// 循环逻辑
}
consele.log(i);	// 5 

改成 let 之后,这个问题就消失了,因为 迭代变量 的作用域 仅限于 循环块 内部:

for ( let i = 0;i < 5 ; i++){
	// 循环逻辑
}
consele.log(i);	// 报错,提示 i 没有 定义 。(ReferenceError)

在使用 var 的时候,最常见的问题就是对 迭代变量的其他声明 和 修改。

for ( var i = 0;i < 5 ; i++){
	setTimeout(() => {consele.log(i), 0)	// 这是一个延时函数,在 0 毫秒 后 执行 逗哈号 前面的 函数。
}
	// 你可以以为会输出 0、1、2、3、4
	// 实际上会输出:5、5、5、5、5

之所以会这样,是因为在推出循环的时候,迭代变量的保存的是 导致 循环推出 的值 5。在之后执行的延时逻辑时,所有 i 都是同一个变量,因为输出的都是同一个最终值。

而在使用 let 声明迭代变量时,JavaScript引擎在后台为 每一个迭代循环 声明一个新的 迭代变量。
每个setTimeout 引用的都是不同的 变量实列,所以 consele.log(i) 会输出的是我们期望的值,也就是循环执行过程中的每个迭代变量的值。

for ( let i = 0;i < 5 ; i++){
	setTimeout(() => {consele.log(i), 0)	// 这是一个延时函数,在 0 毫秒 后 执行 逗号 前面的 函数。
}
	// 输出 0、1、2、3、4

这种每次迭代声明一个独立变量实列的行为适用于 所有的 for 循环,包括 for - in 、for - of 循环。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值