一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

怎样用函数声明定义具名函数并理解其变量提升特性

时间:2026-06-25 09:09:52 编辑:袖梨 来源:一聚教程网

函数声明完整提升至作用域顶部,可声明前调用;var变量仅声明提升、初始化不提升;同名时函数声明优先于var声明且不被覆盖。

函数声明会提升,但只提升函数名和函数体

函数声明(function foo() {})在 JavaScript 中会被「提升」到当前作用域顶部,意味着你可以在声明前调用它。但注意:只有整个函数定义被提升,不是执行顺序提前,也不是变量赋值式地“运行”了函数。

常见错误是以为 console.log(foo) 在声明前会输出 undefined —— 实际上它输出的是函数对象本身。这是因为提升的是函数定义,而非类似 var 那样的“声明+初始化分离”行为。

  • foo() 在声明前能正常执行(如 foo(); function foo() { console.log('hi'); }
  • typeof foo 在声明前是 "function",不是 "undefined"
  • 如果同名标识符既有函数声明又有 var 声明(如 var foo; function foo() {}),函数声明仍优先被提升,var 声明不会覆盖它

别和函数表达式混淆:const/let 声明的函数不提升

写成 const foo = function() {}const foo = () => {} 是函数表达式,受 const/let 的「暂时性死区(TDZ)」约束——访问未初始化的绑定会直接抛出 ReferenceError,而不是返回 undefined

这跟 var foo = function() {} 也不同:var 版本会提升声明(foo 变量名存在),但初始化(赋值)留在原地,所以声明前读取 foo 得到 undefined,调用会报 TypeError: foo is not a function

  • 函数声明:foo() ✅ 声明前可调用
  • var foo = function() {}foo() ❌ 报 TypeErrorconsole.log(foo)undefined
  • const foo = function() {}foo() ❌ 报 ReferenceError(进入作用域但未初始化)

嵌套函数声明的提升范围仅限于所在函数作用域

在函数内部用 function bar() {} 声明,这个 bar 只会在该外层函数体内被提升,对外不可见,也不会污染外层作用域。

容易踩的坑是误以为嵌套声明会提升到全局——它不会。而且不同浏览器对块级函数声明(比如写在 if 块里)的行为曾有分歧(ES2015 后统一为「仅在块内提升,且具有块级作用域」),但主流环境现在都按标准处理。

  • function outer() { function inner() {} inner(); } 中,inner() 可以在声明前调用
  • 但在 outer() 外部调用 inner() 会报 ReferenceError
  • 避免在非严格模式下依赖块级函数声明,严格模式下它等价于 let 声明(即 TDZ 行为)

实际开发中该选函数声明还是函数表达式?

函数声明适合定义逻辑清晰、需提前使用的工具函数(如递归主入口、事件处理器骨架),尤其在模块顶层或立即执行上下文中;函数表达式更常用于需要控制作用域、延迟初始化、或作为参数传递的场景。

真正容易被忽略的是:函数声明的提升无法跨文件、无法跨 eval 或动态 import() 边界。也就是说,如果你把 function foo() {} 放在一个异步加载的脚本里,它不会“提前”影响当前执行流中的代码。

  • 模块内顶层函数声明可安全前置调用,但不要指望它能在 import 语句之前生效
  • 使用构建工具(如 Webpack/Vite)时,提升行为仍以单个 JS 文件为单位,不跨打包产物边界
  • TS 编译后是否保留提升取决于 target 设置(ES5 保持,ES6+ 一般也保持,但类型擦除不影响运行时行为)

热门栏目