Menu

JavaScript 函数声明:语法、提升与 return

如何在 JavaScript 中声明函数:function 关键字、参数、返回值、提升,以及何时用函数声明、何时用函数表达式。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

函数就是一组有名字的步骤

每当你想给一段逻辑起个名字并重复使用时,就要写一个函数。JavaScript 中最古老、最直接的写法是函数声明:function 关键字后面跟一个名字。

从左往右读:

  • function 是开始声明的关键字。
  • greet 是函数名。
  • (name) 是参数列表,也就是函数接收的输入。
  • 花括号里的代码块是函数体。
  • greet("Ada") 是一次调用。JavaScript 会在 name 绑定为 "Ada" 的情况下执行函数体。

定义函数不会运行它,调用才会。

形参与实参

形参(parameter)是函数定义中的名字,实参(argument)是调用时传入的值。日常交流中两者常被混用,但读错误信息时,这个区别就很重要了。

这里 base 和 exponent 是形参,2 和 10 是实参。JavaScript 按顺序绑定它们:第一个实参对应第一个形参,依此类推。

和某些语言不同,传入的实参数量不对时,JavaScript 不会报错。缺少的会变成 undefined,多出来的会被悄悄忽略。这很灵活,偶尔也是个陷阱;后面的文档会讲默认参数和剩余参数。

return 把值送回去

console.log 是把内容写到输出。return 则把一个值交还给调用者,让调用者可以使用它:

没有 return 的函数会返回 undefined:

return 还会立即退出函数。在主逻辑之前用提前返回处理边界情况,是标准做法:

提前返回可以让函数主体不会变成层层嵌套的 if/else 金字塔。

提升:先调用,后定义

这一点真的会让从其他语言过来的人吃惊。函数声明会被提升:JavaScript 在运行任何代码之前,就把它们移到所在作用域的顶部。这意味着你可以在函数声明之前的行调用它:

这段代码运行正常。在执行之前,引擎会扫描作用域,把 square 注册为一个函数,然后才从上到下执行语句。

这是函数声明与其他创建函数的方式(函数表达式、箭头函数)之间真实存在的行为差异。后者像变量一样被提升:名字是已知的,但要等到那一行运行时才会赋值。下一节会详细讲这个区别。

不过大多数代码风格指南仍然建议先定义函数再调用。提升是一张安全网,而不是值得依赖的写法。

声明与表达式

函数声明作为一条独立的语句存在。函数表达式则出现在需要一个值的地方,最常见的是赋值语句的右侧:

两者都会产生可调用的函数。区别在于:

  • 声明会被完整提升。表达式遵循它所赋值的变量的提升规则(const 和 let 在该行运行之前处于暂时性死区)。
  • 声明必须有名字。表达式可以是匿名的,不过给它命名有助于阅读堆栈跟踪。
  • 声明不能随处出现。在严格模式下,if 代码块里的 function foo() {} 在不同引擎中的表现不一致,那种地方应该改用表达式。

对于文件中大多数顶层的辅助函数,用声明读起来很自然。对于作为参数传递或赋值给属性的函数,通常会选择表达式(或箭头函数)。

命名与风格

函数名是对函数功能的承诺。多花几个字符起一个有描述性的名字,在别人第一次读代码时就能收回成本。

几个值得采用的约定:

  • 函数名应该是动词:fetchProfile、computeTotal、sendEmail。
  • 使用 camelCase,这是 JavaScript 的惯例。
  • 返回布尔值的函数通常以 is、has 或 can 开头:isValid、hasAccess、canEdit。

目标是让调用处读起来像一句话。

一个可运行的小例子

把这些部分组合起来:参数、提前返回、有描述性的名字:

一个声明,一个守卫子句,一个清晰的 return。你写的大多数函数都是这个结构。

下一步:箭头函数

函数声明是主力,但现代 JavaScript 大量使用一种更简短的语法:箭头函数,尤其是在回调和单行函数中。它们看起来不一样,在 this 上的行为也不一样,这就是下一页的内容。

常见问题

JavaScript 中如何声明函数?

使用 function 关键字,后面跟函数名、放参数的括号和一个代码块。例如:function greet(name) { return 'Hi, ' + name; }。调用时写出函数名再加括号:greet('Ada')。

JavaScript 中的函数提升是什么?

在代码运行之前,函数声明会被移到所在作用域的顶部,所以你可以在函数定义之前的行调用它。这只适用于 function 声明;赋值给 let 或 const 的函数表达式和箭头函数不会以同样的方式被提升。

函数声明和函数表达式有什么区别?

声明作为一条独立的语句存在(function greet() {}),并且会被提升。表达式把函数赋值给一个变量(const greet = function() {}),遵循普通变量的提升规则。声明按定义必须有名字;表达式则常常是匿名的。

Coddy 编程语言插图

和 Coddy 一起学编程

开始