JavaScript的变量提升和函数提升学习笔记

96 阅读2分钟
  1. 概念: 当使声明一个变量或者函数时,将在代码本身被执行前首先进行处理, 将声明提升到它作用域的顶端去执行, 这个过程被称为变量提升。

思考下面的例子1:

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

会输出什么呢?你是不是以为会输出undefined, 因为var a 声明在a = 2 之后, 被重新赋值了?

其实输出结果为2.

再思考下面的例子2

console(a);
var a = 2;

输出是undefined。 到底发生了什么?

js引擎会在解释JavaScript代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。即,包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。

当我们看到var a = 2时,JavaScript实际上会将其看成两个声明:var a;和a = 2;。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。

例子1的真实处理流程为:

var aa = 2;
console.log(a)

例子2的处理流程为:

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

这个过程是变量和函数声明从它们在代码中出现的位置被移动到了作用域的最上面, 这个过程就叫提升。

  • 注意: 只有声明本身会被提升,而赋值和其他运行逻辑会留在原地。

  • 注意:函数声明会被提升, 函数表达式不会被提升。

看下面的例子3:

foo();
function foo() {  //函数声明
    console.log(a); // undeifined
    var a = 2;
}

foo函数的声明被提升了,因此第一行可以正常执行。

这段代码实际的执行流程为:

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

函数声明会被提升,但是函数表达式不会被提升,看下面的例子

foo(); //报TypeError错误
//函数表达式
var foo = function bar() {
    //...
}

这段程序中的变量标识符foo()被提升并分配给所在作用域,因此foo()不会导致ReferenceError。但是foo此时并没有赋值(如果它是一个函数声明而不是函数表达式,那么就会赋值)。foo()由于对undefined值进行函数调用而导致非法操作,因此抛出TypeError异常。