javascript之变量提升与函数提升

334 阅读3分钟

前言

从概念的字面意义上说,"变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。


不多说,直接撸代码吧 ~~~///(^v^)\\\~~~

正文

什么是变量提升?

javascript在被解析的时候,会有一个预解析阶段,这个时候解析器会将当前上下文环境中的所有变量(不包括es6中的let和const声明)和函数声明提升到最前面。

先来看下面的代码:

    'use strict';
    
    console.log(a); // undefined
    var a = 1;
    console.log(a); // 1

那么在代码被解析的时候,就是这样:

    'use strict';
    
    var a;
    
    console.log(a); // undefined
    
    a = 1;
    
    console.log(a); // 1

那么这个过程就很好理解了。

但是如果有多个同名变量呢?

同名变量声明

同一作用域下,对于同名变量声明,采用的是忽略原则,后声明的会被忽略,变量的赋值,会采取覆盖原则。

  • 同一作用域下同名变量声明

看如下代码:

    'use strict';
    
    console.log(a); // undefined
    
    var a = 1;
    
    console.log(a); // 1
    
    var a = 2;
    
    console.log(a); // 2

解析后的代码如下:

    'use strict';
    
    var a;
    
    console.log(a); //undefined
    
    a = 1;
    
    console.log(a); // 1
    
    a = 2;
    
    console.log(a); // 2
  • 不同作用域下同名变量声明

代码如下:

    'use strict';
    
    console.log(a); // undefined
    
    var a = 1;
    
    function b() {
    
        console.log(a); // undefined
        
        var a = 2;
        
        console.log(a); // 2
    };
    
    b();

解析后的代码如下(此处涉及到的执行上下文环境和作用域会另有文章详细说明):

  1. 首先进入全局上下文环境,此时代码解析如下:

    'use strict';
    
    function b() {
        console.log(a);
        var a = 2;
        console.log(a);
    };
    
    var a;
    
    console.log(a); // undefined
    
    a = 1;
    
    b();

  2. 当执行到调用b函数的时候,进入b函数的上下文环境,b函数的代码被解析时,如下:

    var a;
    
    console.log(a); // undefined
    
    a = 2;
    
    console.log(a); 2

在不同作用域中,就近原则,如果在当前作用域中找到,则不再向上一级作用域查找,如果没找到,则会找上一级作用域,一直找到全局作用域。

所以下面只讨论同一作用域下的情况。

同名函数声明

同一作用域下,对于同名函数声明,采用的是覆盖原则,先声明的会被覆盖。

代码如下:

    'use strict';
        
    console.log(a); // function a() { console.log(2) }
    
    function a() {
        console.log(1);
    };
    
    function a() {
        console.log(2);
    };
    
    console.log(a); // function a() { console.log(2) }

解析后的代码如下:

    'use strict';
    
    function a() {
        console.log(2);
    };
    
    console.log(a); // function a() { console.log(2) }
    
    console.log(a); // function a() { console.log(2) }

同一作用域下,同名的函数声明和变量声明

对于同名的函数声明和变量声明,采用的是忽略原则,函数声明会提升到变量声明之前,变量声明会被忽略,函数声明有效。

代码如下:

    'use strict';
    
    console.log(a); // function a() {}
    
    var a;
    
    function a() {};

解析后的代码如下:

    'use strict';
    
    function a() {};
    
    console.log(a); // function a() {}

如果存在赋值操作,就会采取覆盖原则。
看如下代码:

    'use strict';
    
    console.log(a); // function a() {}
    
    var a = 1;
    
    function a() {};
    
    console.log(a); // 1

解析后的代码如下:

    'use strict';
    
    function a() {};
    
    console.log(a); // function a() {}
    
    a = 1;
    
    console.log(a); // 1

总结

  • 同一作用域下,对于同名变量声明,采用的是忽略原则,后声明的会被忽略,变量的赋值,会采取覆盖原则。
  • 同一作用域下,对于同名函数声明,采用的是覆盖原则,先声明的会被覆盖。
  • 同一作用域下,对于同名的函数声明和变量声明,采用的是忽略原则,函数声明会提升到变量声明之前,变量声明会被忽略,函数声明有效。

如果有遗漏或者不对的地方,还请指正,先谢过~~~///(^v^)~~