JS红宝书学习-第3章 语言基础 --变量_let
3.3 变量-let
let变量的声明和使用方法和var很相似,但是他俩最大的区别在于,let属于块级作用域,而var是函数作用域。例:
// var在同一函数内都可使用
if(true){
var age = 18;
console.log(age); // 18
}
console.log(age) // 18
// 但是let就只能在{}代码块中生效
if(true){
var name = "靓仔";
console.log(name); // 靓仔
}
console.log(name) // 未定义
同时let也不允许在同一作用域内重复声明
let name;
let name; // SyntaxError;name已经声明过了
但是你可以在不同作用域/代码块中声明。
if(true){
let name; // 一家就一个,优生优育
}
if(true){
let name; // 我是隔壁的
}
let name = "靓仔";
console.log(name); // 没错我是,靓仔
if(true){
let name = "帅哥";
console.log(name); // 没错我是,帅哥
}
那么let有什么自己的特点呢:
1.暂时性死区
let是不能像var一样在作用域进行变量提升的。也就是说你得先声明在使用,否则报错。例:
console.log(name); // ReferenceError:name未定义
let name = "张三";
虽然js引擎也会注意到后面let声明了,但是在此之前不能以任何方式来引用未声明的变量。在声明之前的瞬间被称为"暂时性死区",在此阶段引用任何后面才声明的变量都会抛出ReferenceError。
所以我们在开发过程中尽量都要先声明再使用。
2.全局声明
与var不同,使用let在全局作用域中合适呢个名不会成为window对象的属性但是var会。不过let声明仍然会在页面的生命周期内存在,所以注意不要重复声明一个变量,否则会要出SyntaxError错误哟。
3.条件声明
在使用var声明变量时,由于声明会被提升,js引擎会自动将多余的声明在顶部合并为一个声明。因为let的作用域为块,所以不可能检查前面是否已经使用了let声明过同名变量,同时也就不可能在没有声明的情况下声明它。
这是不论使用typeof还是try/catch都无法完美解决,所以let这个关键字不能依赖于条件声明。例:
<script>
let name = 'Nicholas';
let age = 36;
</script>
<script>
// 假设脚本不确定页面中是否已经声明了同名变量
// 那它可以假设还没有声明过
if (typeof name === 'undefined') {
let name;
}
// name 被限制在 if {} 块的作用域内
// 因此这个赋值形同全局赋值
name = 'Matt';
try {
console.log(age); // 如果 age 没有声明过,则会报错
} catch (error) {
let age;
}
// age 被限制在 catch {}块的作用域内
// 因此这个赋值形同全局赋值
age = 26;
</script>
4.for循环中的let声明
var的作用范围为函数作用域,在使用循环时会出现渗透到循环外,但是改为let就不会出现这个问题。例:
//var会出现渗透
for (var i = 0; i < 3; i++) {
// 我在循环
}
console.log(i); // 3
//let不会,因为每次都是新的
for (let i = 0; i < 3; i++) {
// 我在循环
}
console.log(i); // ReferenceError: i 没有定义
因为let每次循环都会使用一个新的值,而var是同一个值,所以会出现很多奇怪的东东,如:
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
// 在此过程中是因为推出循环的时候,i保存的值为5,之后进行超时任务时因为i都是同一个变量就会出现,全是5的现象了。
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
// 而let会输出 0、1、2、3、4
// let就是上面说的每次都变为新的。
加油。

浙公网安备 33010602011771号