js变量提升与函数提升

从别人给我的一道题目说起,请问执行下面语句后的输出结果

var a = 3;
function test(){
  console.log(a);
  a(4);
  function a(b){
    a = b;
  }
  console.log(a);
}
console.log(a);
test();

我最初的答案是:

3
3
4

其实应该是

3
function a(b)
4

这道题包含了了函数提升与变量优先级的问题。为了更好地理解这个复合问题,我们一个一个说起。

变量提升#

意思是你代码中声明变量的所在行,其实并不是真正声明的地方,javascript编译时会统一将声明提升到作用域的最上方。

比如当你写下这行代码时:

var a = 3;

编译器会将变量声明提升到代码顶部,但是赋值仍然在原来的地方,变为:

var a;
a = 3;

举个例子:

var a = 3 ;
console.log(a);
console.log(b);
var b = 2 ;

其输出结果为:

3
undefined

因为其实际编译代码为

var a,b;
a = 3;
console.log(a);
console.log(b);
b = 2;

那现在问题升级一下,引入作用域的概念

var a = 3;
function test(){
  console.log(a);
  a = 4;
  console.log(a);
}

其结果为:

3
4

恩,我不知道有没有迷惑到你,反正我被我自己迷惑到了,我们再来下一题

var a = 3;
function test(){
  console.log(a);
  var a = 4;
  console.log(a);
}
test();

其结果为:

undefined
4

这里要先说一下同名变量优先级,在同一作用域内,两个同名变量中,局部变量的优先级 > 全局变量的优先级,即test方法中的a会覆盖外部的a。

再回到变量提升,所以test方法在编译后实际是这样的

function test(){
  var a ; // 变量声明提升到方法顶部
  console.log(a);
  a = 4; // 赋值仍然在原处进行
  console.log(a);
}

变量作用域#

所有不用var声明的变量都是全局变量
在函数体内,同名的局部变量或参数优先级会高于同名局部变量,即

var a = 3;
function test() {
  var a = 4;
  console.log(a);
}
test();
console.log(a);

会输出

4
3

函数提升#

变量提升理解了,函数提升会好理解一些,函数的声明会提到作用域的顶端,但不同的是,函数提升会将其方法体的内容一起提升,举例来说

function test(){
  test1();
  var b = 5;
  function test1(){
    console.log(b);
  }
}
            
test();

会被编译为

function test(){
  var b;
  function test1(){
    console.log(b);
  }
  test1();
  b = 5;
}
            
test();

输出

undefined

函数声明方式分为两种,函数声明(函数式声明)和函数表达式(变量式声明),只有函数声明才会执行函数提升

console.log(a);
console.log(b);

// 函数声明 执行函数提升
function a(){}

// 函数表达式 不执行函数提升 但可以看成是变量提升
var b = function(){}

输出

function a()
undefined

最后,再看下这个问题

var a;
function a(){
  console.log(2);
}

console.log(a);

结果到底会是undefined还是function?输出如下

function a()

那再加强一下

var a;
function a(){
  console.log(2);
}

console.log(a);
a();
a = 3;
console.log(a);

输出

function a()
2
3

函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。现在应该明白最上方那道题为什么会是这个结果了吧?其编译过程如下:

var a;
function test() {
    function a(b) {
        a = b;
    }
    console.log(a); // functing a(b)
    a(4);
    console.log(a); // 4
}
a = 3;
console.log(a); // 3
test();

你可能感兴趣的:(js变量提升与函数提升)