Skip to content

ES6 - 函数

函数是 JavaScript 中的基本构建块,允许您封装一段可多次执行的代码。ES6 (ECMAScript 2015) 及后续版本为函数语法和功能引入了多项强大的增强。

会被提升 (Hoisted) 到其作用域的顶部,这意味着可以在代码中定义之前调用它们。

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

赋值给一个变量。不会被提升;只能在赋值之后调用。

const add = function(a, b) {
return a + b;
};
console.log(add(5, 3)); // Output: 8

箭头函数提供了一种更简洁的语法来编写函数表达式,并在处理 this 方面有一个重要的区别:它们词法绑定了 this,这意味着箭头函数内部的 this 指向其外部(封闭)词法作用域的 this 值。它们不适用于所有情况(例如,需要自己 this 上下文的方法,或作为构造函数)。

  • 基本形式:(param1, param2) => { statements }
  • 单个参数(括号可选):param => { statements }
  • 无参数:() => { statements }
  • 单个表达式(隐式返回,省略花括号和 return 关键字):(param1, param2) => expression
const multiply = (x, y) => x * y;
console.log(multiply(4, 5)); // 输出: 20
const square = num => num * num; // 单个参数时括号可选
console.log(square(7)); // 输出: 49
const sayHi = () => console.log("Hi there!");
sayHi(); // 输出: Hi there!
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // 输出: [2, 4, 6, 8]
function Timer() {
this.seconds = 0;
// 在传统函数中,setInterval 内部的 'this' 将是全局对象或 undefined (严格模式下)
// setInterval(function() {
// // 这里的 'this' 不是 Timer 实例
// this.seconds++;
// console.log(this.seconds);
// }, 1000);
// 箭头函数从 Timer 构造函数作用域继承 'this'
setInterval(() => {
this.seconds++;
console.log(`Timer (lexical this): ${this.seconds}`);
}, 1000);
}
// 在浏览器/Node 环境中取消注释运行此示例
// const myTimer = new Timer();

默认参数值 (Default Parameter Values) (ES6):

Section titled “默认参数值 (Default Parameter Values) (ES6):”

您可以为函数参数指定默认值。如果未提供该参数的实参或实参为 undefined,则使用默认值。

function greetUser(name = "Guest", message = "Welcome") {
console.log(`${message}, ${name}!`);
}
greetUser(); // 输出: Welcome, Guest!
greetUser("Alice"); // 输出: Welcome, Alice!
greetUser("Bob", "Good morning"); // 输出: Good morning, Bob!

剩余参数语法 (...paramName) 允许函数接受不确定数量的参数并将其作为一个数组。它必须是函数定义中的最后一个参数。

function sumAll(...numbers) {
let total = 0;
for (const num of numbers) {
total += num;
}
return total;
}
console.log(sumAll(1, 2, 3)); // 输出: 6
console.log(sumAll(10, 20, 30, 40, 50)); // 输出: 150
console.log(sumAll()); // 输出: 0

函数调用中的展开语法 (Spread Syntax) (...) (ES6):

Section titled “函数调用中的展开语法 (Spread Syntax) (...) (ES6):”

展开语法允许将可迭代对象(如数组)在函数调用中展开为单个参数。

function calculateProduct(a, b, c) {
return a * b * c;
}
const values = [2, 3, 4];
console.log(calculateProduct(...values)); // 相当于 calculateProduct(2, 3, 4) -> 输出: 24

函数也可以使用 Function 构造函数动态创建:new Function(arg1, arg2, ..., functionBody)。但是,由于安全风险(类似于 eval())和性能影响(函数体在运行时解析),通常不建议使用此方法。

调用自身的函数称为递归函数。递归对于解决可以分解为更小、自相似子问题的问题很有用。需要一个基本情况来停止递归。

function factorial(n) {
if (n < 0) return undefined; // 阶乘对于负数未定义
if (n === 0 || n === 1) {
return 1; // 基本情况
} else {
return n * factorial(n - 1); // 递归步骤
}
}
console.log(factorial(5)); // 输出: 120

IIFE 是一个被定义后立即执行的函数。在历史上,IIFE 常用于为变量创建私有作用域,以避免污染全局作用域(使用 var 时)。随着 ES6 let 和 const 提供了块级作用域,以及模块提供了真正的封装,IIFE 在作用域管理方面的需求有所减少,但它们仍然可以用于初始化或创建闭包。

(function() {
const message = "This is from an IIFE!";
console.log(message);
})();
// 在这里无法访问 message

生成器函数 (Generator Functions) (ES6):

Section titled “生成器函数 (Generator Functions) (ES6):”

生成器函数(function* name() { ... })是一种特殊的函数,可以暂停和恢复执行,从而允许它们随时间产生一系列值。它们使用 yield 关键字来暂停并返回一个值。调用生成器函数时,它会返回一个迭代器 (iterator) 对象。

function* countUpTo(max) {
let count = 1;
while (count <= max) {
yield count++; // 暂停并生成 (yield) 当前计数
}
}
const counter = countUpTo(3);
console.log(counter.next()); // { value: 1, done: false }
console.log(counter.next()); // { value: 2, done: false }
console.log(counter.next()); // { value: 3, done: false }
console.log(counter.next()); // { value: undefined, done: true }
// 也可以与 for...of 循环一起使用
for (const num of countUpTo(3)) {
console.log(`For...of: ${num}`);
}

生成器是高级异步模式的基础,例如 async/await 中使用的模式(尽管 async/await 本身是 Promise 之上的更高层抽象)。