文章目录
一、let相关特性
1. let 声明的全局变量不是全局对象window的属性
-
再说这个之前先了解下ES5之前的声明方式
- 在ES5中写var和不写var区别
- 使用 var 表示是在当前的作用域内声明一个变量
- 如果是在函数内声明就是函数中的作用域变量
- 如果是在函数外就是全局作用域变量
- 如果不写 var js在编译的时候会在 window 这个全局对象上定义一个属性
-
可以通过delete来测试以上所说
delete 只能用于删除对象上的属性 并不能够删除变量
var a = 5 console.log(a) => 5 delete a console.log(a) => 5 console.log(window.a) => 5 b = 6 console.log(b) => 6 delete b console.log(b) // 当前的b已经被删除掉了 报错 console.log(window.b) // undefined
注意这边的window.a 和 window.b 都能够输出内容是因为 js 早期的作者将 window 顶层对象和 全局变量进行了挂钩 (也是败笔之一,很容易污染window对象)=> 使用 let 声明变量就可以很好的解决这个问题
let aa = 5 console.log(aa) // 5 console.log(window.aa) // undefined
2. 用let定义变量不允许重复声明
let a = 6
let a = 7
// 这种的声明是不被允许的 会报 Identifier 'a' has already been declared
3. let声明的变量不存在变量提升
// 使用var定义 具备变量提升
console.log(a) => undefined
var a = 5
等价于
var a
console.log(a)
a = 5
// 使用let
console.log(a) => Cannot access 'a' before initialization at xxx.js
let a = 5
4. let声明的变量具有暂时性死区[Temporal Dead Zone] 简称TDZ
【暂时性死区 => 防止变量在声明之前使用变量】
var a = 5
if (true) {
a = 6
let a // Cannot access 'a' before initialization 却没有报错
}
【这也会报错 因为在使用的时候还没有声明 也会暂时性死区】
function foo(a = b, b = 2) { // Cannot access 'b' before initialization
console.log(a, b)
}
foo()
【改成先声明再使用的就没有问题】
function foo(a = 2, b = a) {
console.log(a, b)
}
5. let 声明的变量拥有块级作用域
【在 es5 变量的声明中只有全局作用域和函数作用域 并没有块级作用域的概念 {} 内就是块级作用域】
比如:
for (var i = 0; i < 3; i++) {
console.log('循环内:' + i) // 0 1 2
}
console.log('循环外' + i) // 最终的结果 i = 3
--------------------------------------------
if (false) {
var a = 10
}
console.log(a) // undefined
使用let
for (let i = 0; i < 3; i++) {
console.log('循环内:' + i)
}
console.log("循环外" + i) // i is not defined
// 以下两者细微差距
// var 声明变量是可以的 => var 会有变量的提升
if (true) var a = 10
// let 声明变量就会报错 => js 引擎认为不存在块级作用域 => 无法声明变量 => 报错
if (true) let a = 5; // Lexical declaration cannot appear in a single-statement context
案例:
// 要求输出0 1 2
for(var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}
// 上面的结果输出的是 3 3 3
// setTimeout是一个定时器,属于异步函数,异步函数的执行会等待同步函数的执行完成,当for循环执行完成的时候,才开始异步的函数执行 所以会输出3个3
// 改造方式一:闭包,通过将i传进去,锁住i
for(var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j)
})
})(i)
}
// 方式二:使用let
for(let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i)
}, 1000)
}