JavaScript-变量提升与函数提升
前言
什么是变量提升?
变量提升是对JavaScript(hoisting)
执行上下文的一种认识。不管变量是在作用域的那个地方声明的,都会提升到当前作用域
的最顶部。
JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
预解析
预解析 -> 变量提升、函数提升(声明变量和函数) -> 执行代码 、执行赋值
变量提升和函数提升不过是预解析的执行过程。
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
在解析过程中如果函数和变量的名字相同时,此时函数优先。所以上面的代码块会先输出函数a
,在输出1
。
变量提升
预解析时,把变量的声明提升到当前作用域的最顶部,不包括变量的赋值。
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
如上面代码所示,解析之前会报 undefined
,而不是 num is not defined
,就是因为 js引擎
预解析将变量num
已经声明,只是没有赋值。
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
JavaScript 编译时会先将 var y;
声明提升至顶部。 执行时变量已经声明了y,所以输出 1 2。
函数提升
预解析时,把函数的声明提升到当前作用域的最顶部,不包括函数的调用。
函数提升的前提是函数声明,而不是函数表达式。
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
上面的例子会输出:
1 |
|
2 |
|
它们之间存在的差异原因是:
用函数声明创建的函数可以在函数解析后调用(解析时进行等逻辑处理)。
而用函数表达式创建的函数是在运行时进行赋值,且要等到表达式赋值完成后才能调用。
ES6 中没有变量提升
例1
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
会输出Cannot access 'age' before initialization
,无法在初始化前访问age
。
例2
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
上面代码输出: 333 和 0 1 2
的原因是:
Js
是单线程的,setTimeout
是异步宏任务,所以代码执行遇到异步的,就放在事件队列中,等线程中的任务执行完后
才会执行事件队列中的任务。let
是ES6
中声明变量的方式,由自己的作用域块,可以放变量,所以let
绑定for
循环时,每个i
都有自己的值,在这个for
循环中就是满足一次条件向事件队列中添加一个打印事件,且每个事件都有自己的值。var
没有自己的作用域块,for
循环的变量就会后面一个覆盖前一个,当循环完毕时i
就取的是最后一次的值.
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!