深刻解析变量声明提高和函数声明提高

JS运行阶段

JavaScript的运行阶段分为预编译阶段执行阶段,今天要讨论的变量声明提高和函数声明提高,就是在这个阶段完成的。函数

在预编译阶段,JS引擎会作一件事情,那就是读取变量的定义肯定其做用域即生效范围。code

  • 变量定义ip

    • 使用var关键字定义的变量,并未赋值的状况下,该变量的值是undefined
  • 变量做用域作用域

    • 全局变量的做用域遍及全局
    • 局部变量的做用域仅在于函数内部
    • 函数内部的同名变量或参数其优先级高于全局同名变量

变量声明提高

先看一个简单示例:io

var name = 'ryan';

function say(){
  console.log(name); //输出:undefined
  var name = 'zoe';
  console.log(name); //输出:'zoe'
}

say();

解析:上述代码从结果看,say函数执行第一次打印name时,并未打印全局的name('ryan'),而是打印局部的name(undefined),这是由于在预编译阶段,say函数内部进行了变量声明提高,提高后的执行效果以下:console

var name = 'ryan';

function say(){
  var name; //变量name声明提高至做用域顶部,但未赋值,故为undefined
  console.log(name); //存在局部name,则无视全局name
  name = 'zoe'; //变量赋值保持原位
  console.log(name); //输出:'zoe'
}

say();

函数声明提高

函数的两种建立方式:编译

  • 函数声明
  • 函数表达式

函数声明:function

say(); //输出:'saying'

function say(){
  console.log('saying');
}

函数表达式:变量

say(); //报错:say is not a function

var say = function(){
  console.log('saying');
}

解析:一样地先执行函数,后建立函数,结果倒是不同。缘由在于,经过函数声明的方式,该函数声明(包括定义)会被提高至做用域的顶部,而表达式的建立方式则只提高了变量say至做用域的顶部,此时的say其值为undefined,调用say()天然报错“say不是一个方法”。方法

再来看一个示例:

var say = function(){
  console.log('1');
};

function say(){
  console.log('2');
};

say(); //输出:'1'

解析:预编译阶段进行变量声明提高和函数声明提高后,上述代码执行效果等同于:

var say; //变量声明提高

function say(){ //函数声明提高
  console.log('2');
}

say = function(){ //变量赋值保持原位执行,say函数被覆盖
  console.log('1');
};

say(); //输出'1'

总结:函数声明提高,会将函数的声明和定义全都提高至做用域顶部。
变量声明提高,只提高声明部分(未赋值状态),赋值部分保持原位置不动。

变量声明和函数声明提高的优先级

函数声明提高的优先级要高于变量声明提高。

先看一个简单示例:

console.log(say); //输出:[Function: say]

function say(){
  console.log('1');
};

var say = '2';

console.log(say); //输出'2'

解析:本例中声明的函数和变量同名都是say,且函数声明在先,变量声明在后,按理说第一次打印say值预期会是undefined,然而结果是[Function: say]。

预编译阶段进行变量声明提高和函数声明提高后,上述代码执行效果等同于:

var say = function (){ //函数声明(包括定义)提高
  console.log('1');
};

var say; //只是声明,并不会覆盖say的值

console.log(say); //故输出:[Function: say]

say = '2'; //此时say会被覆盖

console.log(say); //输出'2'

总结:同名状况下,函数声明提高优先级要高于变量声明提高,且提高后该函数声明定义不会被提高后的同名变量声明所覆盖,可是会被后续顺序执行的同名变量赋值所覆盖。

相关文章
相关标签/搜索