# 一.let
前言
- var 定义的变量没有块的概念,可以跨块访问,不能跨函数访问,有变量提升,可重复声明
- let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明
- let 声明的变量只在块级作用域内有效,不存在变量提升,不可以重复声明
- 或者说 let 变量提升了,但是在 let 声明变量前不能使用该变量,这特性叫暂时性死区
- 如果有重复变量
let
会在编译阶段报错
# 1.声明
# 1.1 重复声明
- 在同一个作用域下可以多次声明同一个变量(let 不能重复声明)
var a = 1
function b() {
var a = 2
var a = 4 // 正常运行
}
b()
1
2
3
4
5
6
2
3
4
5
6
报错
var a = 1
function b() {
let a = 2
let a = 4 // 提示 a 已经被声明过了
}
b()
1
2
3
4
5
6
2
3
4
5
6
在不同的作用域声明同一个变量是可以的
let a = 1
function b() {
let a = 2
}
b()
1
2
3
4
5
2
3
4
5
如果用 let 声明过了 就不要再 用 var 了
function b() {
let a = 2
var a = 4 //报错
}
b()
1
2
3
4
5
2
3
4
5
# 2.作用域
# 2.1 块级作用域
- 允许块级作用域任意嵌套
- 外层作用域无法读取内层作用域的变量
- 内层作用域可以定义外层作用域的同名变量
- 函数本身的作用域在其所在的块级作用域之内
"use strict"
function fn() {
console.log("out")
}
;(function () {
if (false) {
function fn() {
console.log("in")
}
}
fn()
})()
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
在用 var 定义变量的时候,变量是通过闭包进行隔离的,现在有了 let,不仅仅可以通过闭包进行隔离,还增加了一些块级作用域隔离。块及作用域用一组大括号定义一个块,使用 let 定义的变量在大括号的外面是访问不到的
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
console.log(i)
// Uncaught ReferenceError: i is not defined
// at <anonymous>:7:13
// (anonymous) @ VM1874:7
// 0
// 1
// 2
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
先执行同步代码,i 报错,然后执行异步代码,由于是块级作用域,let i=0 会保存在{}中
let 支持块级作用域声明的变量只会声明在当前的作用域内
let 可以解决作用域污染的问题 和局部作用域的问题
# 2.2 变量提升
console.log(a) // 块级作用域,预解释阶段变量不会提升,此处没有找到变量a会报错
let a = 1
1
2
2
- 2.
暂存死区
如果作用域内有这样一个变量,这个作用域内就会绑定这个变量,不会继续向上查找
let a = 1
{
console.log(a) // a is not defined
let a = 2
}
1
2
3
4
5
2
3
4
5
console.log(a)首先会在{}这个作用域中查找 a 变量,因为 a 在这个作用域中已经声明过,但是 let 没有变量提升,所有会报错
同样
let a = 1
{
console.log(a) // 1
a = 2
}
1
2
3
4
5
2
3
4
5
# 3.实现
实现块及作用域
if (true) {
let name = "abc"
}
console.log(name) // ReferenceError: name is not defined
1
2
3
4
2
3
4
不会污染全局对象
if (true) {
let name = "abc"
}
console.log(window.name) // undefined
1
2
3
4
2
3
4
for 循环中也可以使用 i
for (let i = 0; i < 3; i++) {
console.log("out", i)
for (let i = 0; i < 2; i++) {
console.log("in", i)
}
}
// out 0 in 0 in 1 out 1 in 0 in 1 out 2 in 0 in 1
1
2
3
4
5
6
7
2
3
4
5
6
7
重复定义报错
if (true) {
let a = 1
let a = 2 //Identifier 'a' has already been declared
}
1
2
3
4
2
3
4
不存在变量的预解释
for (let i = 0; i < 2; i++) {
console.log("inner", i) // i is not defined
let i = 100
}
1
2
3
4
2
3
4
闭包的新写法
// 以前
;(function () {})()
// 现在
{
}
1
2
3
4
5
2
3
4
5
← ECMAScript6 二.const →