JavaScript中“作用域提升”实为变量提升和函数提升,发生在执行上下文创建时;函数声明被完整提升并优先覆盖同名变量,函数表达式仅按变量规则处理,let/const不提升且存在暂时性死区。

JavaScript 中的“作用域提升”实际是预编译阶段对声明的处理,更准确叫法是 变量提升(Hoisting) 和 函数提升。它不发生在作用域本身,而是在执行上下文创建时,对当前作用域内的声明进行提前登记。函数表达式和函数声明在这一过程中待遇完全不同——核心差异在于:函数声明会被完整提升,函数表达式只按变量规则处理。
函数声明优先被完整提升
函数声明(function foo() {})在预编译阶段直接进入变量对象(VO),整个函数体都可用。这意味着你可以在声明前调用它:
foo(); // 正常执行function foo() { console.log('hi'); }
即使同名的 var 声明出现在它前面,函数声明仍会覆盖该变量的初始 undefined 状态——因为函数提升优先级更高。
函数表达式只享受变量提升待遇
函数表达式(如 const bar = function() {} 或 var baz = () => {})本质是赋值操作。引擎只提升左侧变量名(对 var 是声明+初始化为 undefined;对 let/const 则不提升,进入暂时性死区),函数体本身不会提前存在:
立即学习“Java免费学习笔记(深入)”;
bar(); // TypeError: bar is not a function(如果用 var)或 ReferenceError(如果用 let/const)var bar = function() { console.log('bye'); };
此时 bar 在声明前是 undefined,不是函数,自然无法调用。
同名冲突时函数声明胜出
当函数声明与变量声明同名,比如:
console.log(typeof a); // "function"var a = 1;function a() {}
预编译顺序是:先扫描并提升 function a(),再提升 var a(但因 a 已存在,这步被忽略)。所以首次访问 a 得到的是函数。后续执行 var a = 1 是赋值操作,会把函数覆盖为数字 1。
let/const 不参与传统提升,但有暂时性死区
let 和 const 声明的变量(包括用于函数表达式)不会被提升到作用域顶部,访问它们在声明前会直接报 ReferenceError。例如:
console.log(fn); // ReferenceErrorconst fn = () => 'ok';
这种机制避免了 var 提升带来的隐蔽错误,也意味着函数表达式配合 let/const 完全不具备提前调用能力。


















