JavaScript笔记:提升

本文探讨了JavaScript中函数作用域和块作用域的行为一致性,解释了变量声明如何与作用域相关联。深入剖析了提升机制,包括变量声明、函数声明及函数表达式的提升过程,以及函数声明和变量声明之间的优先级差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数作用域和块作用域的行为是一样的,可以总结为:任何声明在某个作用域内的变量,都将附属于这个作用域。

但是作用域同其中的变量声明出现的位置有某种微妙的联系,而这个细节正是我们将要讨论的内容。

提升

直觉上会认为 JavaScript 代码在执行时是由上到下一行一行执行的。但实际上这并不完全正确,有一种特殊情况会导致这个假设是错误的。

引擎会在解释 JavaScript 代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。

因此,正确的思考思路是,包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。

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

只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。如果提升改变了代码执行的顺序,会造成非常严重的破坏。

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

foo 函数的声明(这个例子还包括实际函数的隐含值)被提升了,因此第一行中的调用可以正常执行。

另外值得注意的是,每个作用域都会进行提升操作。尽管前面大部分的代码片段已经简化了(因为它们只包含全局作用域),而我们正在讨论的 foo(..) 函数自身也会在内部对 var a 进行提升(显然并不是提升到了整个程序的最上方)。

注意,函数声明会被提升,但是函数表达式却不会被提升。

foo(); // 不是 ReferenceError, 而是 TypeError!
var foo = function bar() { // ...
};

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

函数优先

函数声明和变量声明都会被提升。但是一个值得注意的细节(这个细节可以出现在有多个“重复”声明的代码中)是函数会首先被提升,然后才是变量。

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

这个代码片段会被引擎理解为如下形式:

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

注意,var foo尽管出现在function foo()...的声明之前,但它是重复的声明(因此被忽略了),因为函数声明会被提升到普通变量之前。

尽管重复的 var 声明会被忽略掉,但出现在后面的函数声明还是可以覆盖前面的。

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

一个普通块内部的函数声明通常会被提升到所在作用域的顶部,这个过程不会像下面的代码暗示的那样可以被条件判断所控制:

foo(); // "b"
var a = true; 
if (a) {
    function foo() { console.log("a"); } 
}else {
    function foo() { console.log("b"); }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值