JavaScript的变量提高机制

变量提高

JavaScript的变量提高有两种,用var声明的变量以及用function声明的变量。javascript

用var声明的变量

咱们先来看下面这段代码,a的值是多少java

代码1编程

console.log(a);

var a;

按照以往编程语言的思路来看,代码自上而下运行,按这种思路,会报错,由于执行到第2行时,变量a尚未定义,因此会报错a is not defined编程语言

然而事实上答案是undefined函数

好,抱着疑惑,咱们看下面的代码code

var a;
console.log(a);

咱们发现,这两段代码是同样的,那么又有一个新的问题,是否是有没有var a都无所谓,它的答案始终是undefined,才形成了觉得变量会提高的错觉,因而我写了代码3ip

代码3作用域

console.log(a);

好,它终于报错了,因此这证实了javaScript代码并非自上而下执行的,至少从表面看上面是这样的。开发

因而咱们再看代码4编译器

代码4

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

由于变量提高嘛,因此答案是2,然而事实上,它依然是undefined,why?

这时候咱们有请编译器这位负责语法分析及代码生成等脏活累活的大佬。

编译器在看到var a = 2;,它会将其看作两个声明,var a;a = 2,第一个声明在编译阶段进行,第二个声明会被原地等待执行阶段。

也就是说上面代码,会变成下面的这段代码

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

因此最终会是undefined

好,我在啰嗦一下,看这段代码5

代码5

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

我想你们应该已经知道这段代码执行时的真正顺序及其答案了,没错,答案是2,但我想说的是把第2行给注释掉,答案依然是2,但这个和变量提高没啥关系了,是严格模式与非严格模式的锅,在非严格模式下容许开发者能够不使用声明变量的关键字,但在严格模式下是不能够的,它会报错的。

用function声明的变量

var同样,function声明的变量依然会提高。

log(5);

function log(mes){
    console.log(mes)
}

按照以前的变量提高的理解,这段代码的真正顺序是这样的,

function log(mes){
    console.log(mes)
}

log(5);

很好,很正确,那么再看下一段代码

log(5);

var log = function(mes){
    console.log(mes)
}

它报错了,log is not a function,从这里咱们能够看出,这种函数表达式是不会被提高的,只有函数声明才会被提高,试着在最前面新增一行代码console.log(log),会先输出undefined

因此这里的真正顺序是

var log;
log(); //这时候只是声明了log这个变量,并非函数,却用函数的方法调用它,因此会报错,说这不是一个函数。
log = function(mes){
    console.log(mes)
}

在function里用var声明变量

咱们虽然知道,var声明的变量会提高,但并不知道会提高到哪一个程度。

在此以前来看一段代码

var a = 4;

function foo(){
    var a = 5;
    console.log(a);

}
foo();

console.log(a)

答案是5,4,先输出5,再输出4。

var声明的变量是有函数做用域的,因此foo里的a和foo外面的a没有任何关系,这种状况正是我想要的。

再改下代码

function foo(){
    a = 5
    console.log(a);
    var a;
}
foo();

console.log(a)

答案是5,a is not defined

第4行代码输出5,第9行报错。

这种状况就是变量提高只会提高到变量所在的 做用域的顶部,不会提高到父级做用域。

所以能够得出一个结论:变量提高只会将变量提高到本身所在的做用域的顶部

函数优先

既然用varfunction的变量都有提高的功能,那若是同一个变量用这两种都声明会怎样,好吧,看标题就知道了,函数优先。

具体看下代码

foo();

var foo;

function foo(){
    console.log(1)
}

foo = function(){
    console.log(2)
}

答案是1

这段代码其实这样子的

function foo(){
    console.log(1)
}

foo();// 1

foo = function(){
    console.log(2)
}

仔细一看,var foo;没了,没错,它被引擎忽略了,认为重复声明因此把它抛弃了。

好,既然var声明的变量比不了函数声明,那就用函数声明,屡次声明同个变量。

foo()
function foo(){
    console.log(1);
}
foo()
function foo(){
    console.log(2);
}
foo()
function foo(){
    console.log(3);
}

foo()

foo声明了三次,调用了四次,每次调用的结果都是3,因此最后的函数声明会覆盖以前的函数声明

可是var还想挣扎一下,以为仍是有必要证实本身的存在感的。

foo()
function foo(){
    console.log(1);
}
var foo;
foo()
foo = function(){
    console.log(2);
}
foo()
function foo(){
    console.log(3);
}

foo()

仔细看,中间那部分代码改了,依次输出3,3,2,2

虽然var foo被忽略了,但下面的函数仍是有用的,这段代码能够当作是这样的

function foo(){
    console.log(3);
}

foo();//3
foo();//3
foo = function(){
    console.log(2);
}
foo();//2
foo();//2

在普通块内部声明函数

以前是在做用域声明函数,如今来块里面声明函数

function foo(){

    console.log(b); // undefined
    b(); //TypeError: b is not a function

    var a = true;

    if(a){
        function b(){
            console.log(2)
        }
        //下面这段代码和上面的结果同样
        // var b = function(){
  //           console.log(2)
  //       }
    }
    //b() --> 这里会被执行

}

foo()

从上面看上去,b是undefined,证实这个变量仍是有的,只不过它并非一个函数,这状况和用函数表达式差很少。

总结

  • 提高分为函数声明提高和变量声明提高
  • 声明变量用var,声明函数用function
  • 变量提高会将变量提高到本身所在做用域的顶部
  • 函数表达式不存在提高的机制。
  • 函数声明和变量声明同时声明同一个标识符时,函数声明优先
  • 多个函数声明同一个标识符时,最后一个声明覆盖先前的声明
相关文章
相关标签/搜索