JavaScript 函数声明方式:技术与实践指南
传统函数声明(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");理解差异的类比
打个比方:函数声明 是厨房里刻在石头上的菜谱,一直在那里,上班之前谁都知道去哪找。函数表达式 是你随手写的便利贴,只有写完贴到墙上之后才有人能照着做。箭头函数 更像是脑子里的一条捷径,借着当前正在做的事情的上下文,顺手完成个小任务,不用动用整个厨房。