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 协议 ,转载请注明出处!