## 变量提升 先说三句总结性的话: - let 的「创建」过程被提升了,但是初始化没有提升。 - var 的「创建」和「初始化」都被提升了。 - function 的「创建」「初始化」和「赋值」都被提升了。 ### 变量提升的规律 在进入一个执行上下文后,先把 var 和 function 声明的变量前置,再去顺序执行代码。 PS:作用域分为全局作用域和函数作用域,用var声明的变量,只在自己所在的所用域有效。 我们举例来看看下面的代码。 **代码 1:** ```javascript console.log(fn); var fn = 1; function fn() { } console.log(fn); ``` 相当于: ```javascript var fn = undefined; function fn() { } console.log(fn); fn = 1; console.log(fn); ``` 打印结果: ![](http://img.smyhvae.com/20180321_1810.png) **代码 2:** ```javascript console.log(i); for (var i = 0; i < 3; i++) { console.log(i) } ``` 相当于: ```javascript var i = undefined; console.log(i); for (i = 0; i < 3; i++) { console.log(i); } ``` 打印结果: ![](http://img.smyhvae.com/20180321_1817.png) **代码 3:** ```javascript var a = 1; function fn() { a = 2; console.log(a) var a = 3; console.log(a) } fn(); console.log(a); ``` 相当于: ```javascript var a = undefined; function fn() { var a a = 2 console.log(a) a = 3 console.log(a) }; a = 1; fn(); console.log(a); ``` 打印结果: ![](http://img.smyhvae.com/20180321_1827.png) 参考链接: ### 声明时的重名问题 假设`a`被声明为变量,紧接着`a`又被声明为函数,原则是:声明会被覆盖(先来后到,就近原则)。 PS: - 如果`a`已经有值,再用 var 声明是无效的。 - 如果`a`已经有值,紧接着又被赋值,则**赋值会被覆盖**。 举例1: ```javascript var fn; //fn被声明为变量 function fn() {// fn被声明为function,就近原则 } console.log(fn); //打印结果:function fn(){} ``` 举例2: ```javascript function fn() {} //fn被声明为function,且此时fn已经被赋值,这个值就是function的对象 var fn; //fn已经在上一行被声明且已经有值, 再 var 无效,并不会重置为 undefined console.log(fn) //打印结果:function fn(){} ``` 既然再var无效,但是再function,是有效的: ```javascript function fn() {} //fn被声明为function,且此时fn已经有值,这个值就是function的对象 function fn() { //此时fn被重复赋值,会覆盖上一行的值 console.log('smyhvae'); } console.log(fn) ``` 打印结果: ![](http://img.smyhvae.com/20180321_1845.png) ### 函数作用域中的变量提升(两点提醒) **提醒1:** 在函数作用域也有声明提前的特性: - 使用var关键字声明的变量,是在函数作用域内有效,而且会在函数中所有的代码执行之前被声明 - 函数声明也会在函数中所有的代码执行之前执行 因此,在函数中,没有var声明的变量都会成为**全局变量**,而且并不会提前声明。 举例1: ```javascript var a = 1; function foo() { console.log(a); a = 2; // 此处的a相当于window.a } foo(); console.log(a); //打印结果是2 ``` 上方代码中,foo()的打印结果是`1`。如果去掉第一行代码,打印结果是`Uncaught ReferenceError: a is not defined` **提醒2:**定义形参就相当于在函数作用域中声明了变量。 ``` function fun6(e) { console.log(e); } fun6(); //打印结果为 undefined fun6(123);//打印结果为123 ``` ### 其他题目 **20180321面试题:** ```javascript var a = 1; if (a > 0) { console.log(a); var a = 2; } console.log(a); ``` 打印结果: ``` 1 2 ``` 上方代码中,不存在块级作用域的概念。if语句中用var定义的变量,让然是全局变量。 顺便延伸一下,用let定义的变量,是在块级作用域内有效。 ```javascript ``` ```javascript ``` ```javascript ``` ```javascript ``` ```javascript ```