Skip to content

函数定义

JavaScript functions(函数)是基本构建块。它们主要使用 function 关键字或较新的 arrow function(箭头函数)语法来定义。

你可以使用 function declarations(函数声明)、function expressions(函数表达式)和 arrow functions(箭头函数)来定义函数。

Function declaration 定义一个命名的函数。其语法是:

function functionName(parameter1, parameter2) { // 要执行的代码 return result; // 可选 }

声明的函数不会立即执行。它们会被“hoisted”(提升)(参见下文),并在其 scope(作用域)范围内都可用,准备好稍后被调用(或“调用”,invoked)。

// 声明一个函数
function multiply(a, b) {
return a * b;
}
// 调用函数
const product = multiply(5, 10); // product 是 50
关于分号的注意:Function declaration 是一种语句,但与大多数语句不同,它们通常不以分号结尾。然而,JavaScript 的自动分号插入 (Automatic Semicolon Insertion,ASI) 通常可以很好地处理这个问题。

JavaScript function 也可以使用 expression(表达式)来定义。Function expression 可以存储在一个变量中。

最佳实践是使用 const 来定义 function expressions,以防止意外的重新赋值。

// 将一个函数表达式存储在变量中
const calculateSum = function(a, b) {
return a + b;
}; // 这里需要分号,因为它是一个赋值语句的一部分。
// 使用变量调用函数
const sum = calculateSum(4, 3); // sum 是 7

上述示例中的函数是一个匿名函数(anonymous function,没有名称的函数),它被赋值给 calculateSum 变量。存储在变量中的函数使用变量名来调用。

Arrow Functions(箭头函数)(ES6+)

Section titled “Arrow Functions(箭头函数)(ES6+)”

Arrow functions 是在 ES6 中引入的,提供了一种更简洁的语法来编写 function expressions。它们总是匿名的。

// 带有多个参数和块体(block body)的箭头函数
const greet = (name) => {
return `Hello, ${name}!`;
};
// 只有一个参数的箭头函数(括号可选)
const square = x => x * x;
// 没有参数的箭头函数
const getRandom = () => Math.random();
console.log(greet('World')); // 输出: Hello, World!
console.log(square(5)); // 输出: 25

Arrow functions 的主要特点:

  • 语法简洁,特别适用于简单的函数。
  • 它们没有自己的 this 绑定。this 的值继承自外层词法作用域 (lexical scope)。这通常是期望的行为,尤其是在 callbacks(回调函数)中。
  • 它们不能用作构造函数(即不能与 new 关键字一起使用)。
  • 它们没有 arguments 对象。应改用 rest parameters(剩余参数)(...args)。

关于 this 在 arrow functions 中的更多细节,请查阅关于 JavaScript scope(作用域)和上下文(context)的资源。

The Function Constructor(构造函数)

Section titled “The Function Constructor(构造函数)”

JavaScript functions 在技术上可以使用内置的 Function constructor(构造函数)来定义。然而,通常不建议使用这种方法。

// 示例(不推荐)
const multiplyConstructor = new Function("a", "b", "return a * b");
const result = multiplyConstructor(4, 3); // result 是 12

避免使用 new Function() 的原因:

  • 安全风险:它会评估字符串中的代码,类似于 eval()。
  • 性能问题:这样创建的函数 JavaScript 引擎更难优化。
  • 可读性:代码不够清晰,更难调试。

坚持使用 function declarations、function expressions 或 arrow functions。

Hoisting 是 JavaScript 的一种行为,它会将声明(在概念上)移动到其 scope 的顶部,然后再执行代码。

Function Declarations:会被完全 hoisted。这意味着你可以在 function declaration 出现在代码之前调用它。

sayHello(); // 可以正常工作,因为 greet 被提升了

function sayHello() { console.log(“Hello!”); }

Function Expressions 和 Arrow Functions:不会以同样的方式被 hoisted。如果使用 var 定义,变量声明 (var x;) 会被 hoisted,但赋值 (x = function() {...};) 不会。如果使用 let 或 const 定义,变量会被 hoisted 但停留在“暂时性死区”(temporal dead zone)中,直到遇到声明行,因此你不能在此之前访问它。

// tryToCall(); // 这会导致错误(ReferenceError 或 TypeError,取决于使用的是 var/let/const)
const tryToCall = function() {
console.log("Called!");
};
// 或者使用箭头函数:
// const tryToCallArrow = () => console.log("Arrow called!");

理解 hoisting 对于避免意外错误至关重要。使用 let 和 const 通常会导致更可预测的行为。

Immediately Invoked Function Expressions (IIFE)(立即调用函数表达式)

Section titled “Immediately Invoked Function Expressions (IIFE)(立即调用函数表达式)”

Function expression 可以在定义后立即执行。这种模式被称为 IIFE(立即调用函数表达式),以前常被称为自调用函数(self-invoking function)。

IIFE 会自动被调用,因为 expression 后面紧跟着 ()。为了明确它是一个 expression,函数被包裹在括号中。

(function() {
const message = "Hello from IIFE!";
console.log(message); // 这将立即执行
})();
// 使用箭头函数的 IIFE
(() => {
const secret = "This is private to the IIFE.";
console.log(secret);
})();

IIFE 对于创建局部 scope(作用域)、避免污染全局命名空间(global namespace)以及用于一次性设置代码非常有用。

在 JavaScript 中,functions 是“一等公民”(first-class citizens)。这意味着它们可以像任何其他值一样对待:可以赋值给变量,作为 arguments(参数)传递给其他 functions,以及从 functions 返回。

function add(a, b) {
return a * b;
}
const operation = add; // 将函数赋给一个变量
const result1 = operation(4, 3); // result1 是 12
const result2 = add(4, 3) * 2; // 在表达式中使用函数返回值
// result2 是 24

这种灵活性是 JavaScript 功能的核心部分,它支持 callbacks(回调函数)和 higher-order functions(高阶函数)等模式。

虽然 typeof operator 对 functions 返回 "function",但它们在本质上是 JavaScript 中一种特殊类型的 object(对象)。

像 objects 一样,functions 可以有 properties(属性)和 methods(方法)。

arguments.length property(属性)(在非 arrow functions 中可用)返回函数被调用时实际传递的 arguments(参数)数量:

function countArgs(a, b) {
console.log(arguments.length); // 传递的参数数量
// 现代方法:使用剩余参数
// function countArgsModern(...args) { console.log(args.length); }
}
countArgs(1, 2, 3); // 输出: 3

注意:arguments object 是一个类数组 (array-like) object。对于现代 JavaScript,通常最好使用 rest parameters (...args),它提供一个真正的 array(数组)。

toString() method 返回 function 的源代码 (source code) 作为字符串:

function exampleMultiply(a, b) {
return a * b;
}
const funcAsString = exampleMultiply.toString();
console.log(funcAsString);
/* 输出可能为:
"function exampleMultiply(a, b) {
return a * b;
}"
*/
关键术语:定义为 object property 的 function 称为 method(方法)。设计用于创建新 objects(使用 new)的 function 称为 constructor function(构造函数)(arrow functions 不能是构造函数)。