

## 变量提升

先说三句总结性的话：

- 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)

参考链接：<https://github.com/jirengu/javascript-tutorial>


### 声明时的重名问题

假设`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


```










