725 字
4 分钟
JavaScript 变量提升&函数提升

核心定义#

JavaScript 引擎在代码执行前会进行编译阶段,此过程将:

  1. 函数声明整体提升到作用域顶部
  2. 变量声明var)仅提升声明(不提升赋值),初始化为 undefined
  3. 赋值操作非声明代码留在原地 这种机制称为提升(Hoisting),let/const 有暂时性死区(TDZ),在声明前访问会报错。

工作原理#

  1. 编译阶段
    • 扫描作用域内的函数声明和 var 变量
    • 函数声明优先提升(创建函数对象)
    • var 变量初始化为 undefined
  2. 执行阶段
    • 按顺序执行代码
    • 遇到赋值操作时才更新变量值
    • let/const 在执行到声明语句时才初始化
flowchart TD 
	A[编译阶段] --> B[提升函数声明(整体)] 
	A --> C[提升var声明(初始化为undefined)] 
	D[执行阶段] --> E[执行赋值操作] 
	D --> F[执行函数调用] 
	D --> G[let/const初始化(TDZ结束)]

关键点#

  1. 提升优先级:函数声明 > 变量声明(同名时函数覆盖变量)
  2. 函数表达式不提升(如 var foo = function(){}
  3. 块级作用域:ES6 的 let/const 不提升(但有 TDZ)
  4. 重复声明
    • var 允许重复声明
    • let/const 禁止重复声明
  5. 严格模式'use strict' 禁止意外创建全局变量

常见误区#

  1. 误解函数表达式:认为 var foo = function(){} 会整体提升
  2. 混淆函数与变量:同名时误以为变量声明覆盖函数
  3. 忽略 TDZ:在 let 声明前访问变量(报错 vs undefined
  4. 块级函数声明:ES5 非严格模式中块内函数声明行为不一致
  5. 提升范围误判:认为 if 块内的 var 会限制在块作用域(实际函数级)

应用场景#

场景示例提升行为
函数调用在声明前foo(); function foo() {...}正常执行(函数整体提升)
var 提前访问console.log(a); var a = 1;输出 undefined(声明提升)
let 暂时性死区console.log(b); let b = 2;报错 ReferenceError
函数表达式bar(); var bar = () => {...}报错 bar is not a function
同名函数与变量console.log(c); var c; function c(){}输出 ƒ c(){}(函数优先覆盖)
重复声明var d = 1; var d; console.log(d);输出 1(忽略重复声明)

关联知识#

  1. 执行上下文
    • 创建阶段(提升发生)
    • 执行阶段(代码运行)
  2. 作用域链:词法作用域决定变量访问范围
  3. 闭包:函数保留其声明时的作用域链
  4. 严格模式
    • 禁用 with
    • 禁止意外全局变量
    • 对 eval 限制作用域
  5. 模块作用域:ES6 模块自动启用严格模式
  6. 事件循环:提升在同步代码执行前完成

💡 黄金法则

  • 始终使用 const > let > var
  • 函数优先使用声明式(function foo()
  • 避免在块内声明函数(用函数表达式替代) 通过 eslint 规则(如 no-use-before-define)捕获提升相关问题!
JavaScript 变量提升&函数提升
https://website-truelovings-projects.vercel.app/posts/frontend/javascript/javascript-变量提升函数提升/
作者
欢迎来到StarSky的网站!
发布于
2024-08-17
许可协议
CC BY-NC-SA 4.0