ES6中的var, let, const
var, let, const
这三个东西, 经常会被问到。
汇总一下,基本上就是:
var, let, const
有什么区别
?- let, const 有没有
变量提升
(hosting) ? - 什么是
TDZ
?
首先, 我们先整体的看下区别
:
针对这几点, 我们一个个看。
首先, 我们还是先了解一下变量提升
.
看个例子:
console.log(a) // undefined
var a = 1
这里我们可以看到, 第一行中的a虽然还没声明, 但是我们用起来却不会报错。 这种情况, 就是声明的提升。
其实也就是:
var a
console.log(a) // undefined
a = 1
但是, 如果是换成let
, 情况就不一样了:
要理解这个现象, 首先需要搞清楚提升的本质, 理解创建 javascript 变量的三个步骤
:
创建
初始化
赋值
为了便于理解, 我们先看看var
的 创建、初始化和赋值
过程:
function foo(){var x = 1var y = 2
}foo()
执行foo 时, 会有一些过程(部分过程):
- 进入 foo,为 foo 创建一个环境。
- 找到 foo 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
- 将这些变量「初始化」为 undefined。
- 执行代码
- x = 1 将 x 变量「赋值」为 1
- y = 2 将 y 变量「赋值」为 2
也就是说 va
声明, 会在代码执行之前就将 创建变量
,并将其初始化为 undefined
。
这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined
。
接下来看 let 声明的「创建、初始化和赋值」过程
// ...
{let x = 1;x = 2
}
我们看一下过程:
- 找到所有用
let
声明的变量,在环境中创建
这些变量 - 执行代码(注意现在还没有初始化)
- 执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
- 执行 x = 2,对 x 进行「赋值」
这就解释了为什么在 let x 之前使用 x 会报错:
let x = 'global'
{console.log(x) // Uncaught ReferenceError: x is not definedlet x = 1
}
原因有两个
- console.log(x) 中的 x 指的是下面的 x,而不是全局的 x.
- 执行 log 时 x 还没「初始化」,所以不能使用(也就是所谓的
TDZ
, tempory dead zone, 暂时死区)
说到这里, 就都清楚了:
- let 的「创建」过程被提升了,但是初始化没有提升。
- var 的「创建」和「初始化」都被提升了。
function 也是类似的,而且function 的「创建」「初始化」和「赋值」都被提升了。
这一点, 感兴趣的朋友可以自己实验一下。
算了, 直接给个例子吧:
<script>
bar()function bar(){console.log(2)
}
</script>
JS 引擎会有一下过程:
- 找到所有用 function 声明的变量,在环境中「创建」这些变量。
- 将这些变量「初始化」并「赋值」为
function(){ console.log(2) }
。 - 开始执行代码 fn2()`
也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。
这里做一下简单的总结:
函数提升优先于变量提升
.函数提升
会把整个函数挪到作用域顶部
,变量提升
只会把声明
挪到作用域顶部
。var
存在提升
,我们能在声明之前
使用。let
,const
因为存在暂时性死区
,不能在声明前使用
。var
在全局作用域
下声明变量, 会导致变量挂载在window
上, 而另外两者不会
。let
和const
的作用基本一致,但是后者声明的变量不能再次赋值。
ES6中的var, let, const
var, let, const
这三个东西, 经常会被问到。
汇总一下,基本上就是:
var, let, const
有什么区别
?- let, const 有没有
变量提升
(hosting) ? - 什么是
TDZ
?
首先, 我们先整体的看下区别
:
针对这几点, 我们一个个看。
首先, 我们还是先了解一下变量提升
.
看个例子:
console.log(a) // undefined
var a = 1
这里我们可以看到, 第一行中的a虽然还没声明, 但是我们用起来却不会报错。 这种情况, 就是声明的提升。
其实也就是:
var a
console.log(a) // undefined
a = 1
但是, 如果是换成let
, 情况就不一样了:
要理解这个现象, 首先需要搞清楚提升的本质, 理解创建 javascript 变量的三个步骤
:
创建
初始化
赋值
为了便于理解, 我们先看看var
的 创建、初始化和赋值
过程:
function foo(){var x = 1var y = 2
}foo()
执行foo 时, 会有一些过程(部分过程):
- 进入 foo,为 foo 创建一个环境。
- 找到 foo 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
- 将这些变量「初始化」为 undefined。
- 执行代码
- x = 1 将 x 变量「赋值」为 1
- y = 2 将 y 变量「赋值」为 2
也就是说 va
声明, 会在代码执行之前就将 创建变量
,并将其初始化为 undefined
。
这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined
。
接下来看 let 声明的「创建、初始化和赋值」过程
// ...
{let x = 1;x = 2
}
我们看一下过程:
- 找到所有用
let
声明的变量,在环境中创建
这些变量 - 执行代码(注意现在还没有初始化)
- 执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
- 执行 x = 2,对 x 进行「赋值」
这就解释了为什么在 let x 之前使用 x 会报错:
let x = 'global'
{console.log(x) // Uncaught ReferenceError: x is not definedlet x = 1
}
原因有两个
- console.log(x) 中的 x 指的是下面的 x,而不是全局的 x.
- 执行 log 时 x 还没「初始化」,所以不能使用(也就是所谓的
TDZ
, tempory dead zone, 暂时死区)
说到这里, 就都清楚了:
- let 的「创建」过程被提升了,但是初始化没有提升。
- var 的「创建」和「初始化」都被提升了。
function 也是类似的,而且function 的「创建」「初始化」和「赋值」都被提升了。
这一点, 感兴趣的朋友可以自己实验一下。
算了, 直接给个例子吧:
<script>
bar()function bar(){console.log(2)
}
</script>
JS 引擎会有一下过程:
- 找到所有用 function 声明的变量,在环境中「创建」这些变量。
- 将这些变量「初始化」并「赋值」为
function(){ console.log(2) }
。 - 开始执行代码 fn2()`
也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。
这里做一下简单的总结:
函数提升优先于变量提升
.函数提升
会把整个函数挪到作用域顶部
,变量提升
只会把声明
挪到作用域顶部
。var
存在提升
,我们能在声明之前
使用。let
,const
因为存在暂时性死区
,不能在声明前使用
。var
在全局作用域
下声明变量, 会导致变量挂载在window
上, 而另外两者不会
。let
和const
的作用基本一致,但是后者声明的变量不能再次赋值。