Zademy

JavaScript 函数声明方式:技术与实践指南

JavaScript; functions
words 字

传统函数声明(function 声明)

最老牌的形式。function 关键字,跟着一个必须的名字,就这样。它最大的特点是 提升(hoisting),意思是你可以在函数定义的代码行 之前 就调用它。

带参数的示例:

function greet(name) {
	return `Hello, ${name}!`;
}
console.log(greet("World")); // "Hello, World!"

函数表达式

这里函数变成了一个值,赋给一个变量。let、var、const 都行。和声明不同,这种写法 不会被完全提升,执行流没走到赋值那行之前,这个函数压根不存在。

  • 匿名: 没有名字。
  • 命名: 带内部标识符,递归和调试时很有用(栈追踪里能看到它)。

示例:

const sum = function (a, b) {
	return a + b;
}; // 使用 'const' 有助于避免意外重新赋值

箭头函数

ES6 带来的。语法极简,不需要 function 关键字。但最重要的语义差异是:它没有自己的 this,而是从外层词法作用域捕获 this。这一条我自己也踩过好几次坑。

  • 只有一个参数且只有一行代码时,括号、大括号、return 全部可以省掉。

示例:

const square = x => x * x; // 隐式返回

对象和类中的方法定义(简写)

在 对象字面量 或 类 里定义方法的简写,省掉冒号和 function。值得注意的是,这种写法是唯一能访问 super 的。

对象中的示例:

const calculator = {
	value: 10,
	double() {
		return this.value * 2;
	} // 简洁语法
};

异步函数(async)

加了 async 的函数 永远返回 Promise。函数体里可以用 await,以非阻塞方式暂停执行,等 Promise 落定。

示例:

async function fetchData() {
	const response = await fetch("url");
	return response.json();
}

生成器函数(function*)

function* 定义。执行不是连续的,可以用 yield 暂停状态、把控制权还给调用者。

示例:

function* counter() {
	yield 1;
	yield 2;
}

立即调用函数表达式(IIFE)

定义即执行。主要用途是创建 私有作用域,避免全局命名空间污染。模块系统普及之前,这东西到处都是。

示例:

(function () {
	const message = "Private";
	console.log(message);
})();

Function 构造函数(不推荐)

运行时从字符串动态创建函数。有 安全风险,引擎也不好优化。我个人从没用过它,也不建议你用。

示例:

const dynamicSum = new Function("a", "b", "return a + b");

理解差异的类比

打个比方:函数声明 是厨房里刻在石头上的菜谱,一直在那里,上班之前谁都知道去哪找。函数表达式 是你随手写的便利贴,只有写完贴到墙上之后才有人能照着做。箭头函数 更像是脑子里的一条捷径,借着当前正在做的事情的上下文,顺手完成个小任务,不用动用整个厨房。