JavaScript 的“积木”:函数入门与实践
引言:告别重复,拥抱模块化
想象一下,你在写代码时发现,有几段逻辑几乎一模一样,需要在不同的地方反复使用。你是选择每次都复制粘贴,还是希望能像搭积木一样,把这段逻辑封装起来,需要时直接调用?
函数,就是 JavaScript 提供给我们的这种强大的“积木”。它允许我们将一系列相关的语句组合在一起,形成一个独立的功能单元,并给它起一个名字。当你需要执行这个功能时,只需要“喊一声”它的名字(调用函数),代码就会自动执行。
使用函数带来的好处显而易见:
- 代码复用 (Reusability): 同一段逻辑只需编写一次,可以在任意地方多次调用。
- 模块化 (Modularity): 将复杂的程序分解成一个个小的、功能独立的函数,使代码结构更清晰。
- 可维护性 (Maintainability): 修改或修复某个功能时,只需要找到对应的函数进行修改,而不用在整个代码库中到处查找和替换。
- 可读性 (Readability): 有意义的函数名能清晰地表达该段代码的作用,让代码更容易理解。
准备好学习如何创建和使用你自己的 JavaScript “积木”了吗?
一、什么是函数?
简单来说,函数是一段可以被重复调用(执行)的代码块。它通常会接收一些输入(称为参数),执行特定的任务,并可能返回一个输出(称为返回值)。
就像一个榨汁机:你放入水果(输入/参数),它执行榨汁的操作(任务),最后得到果汁(输出/返回值)。
二、定义函数:创建你的“积木”
在 JavaScript 中,主要有以下几种定义函数的方式:
1. 函数声明 (Function Declaration)
这是最常见的方式,使用 function 关键字,后面跟着函数名、一对圆括号 ()(里面可以放参数列表),以及一对大括号 {} 包裹的函数体(包含要执行的代码)。
// 定义一个名为 greet 的函数
function greet() {console.log("Hello there!");
}// 定义一个名为 add 的函数,它接收两个参数 a 和 b
function add(a, b) {let sum = a + b;console.log("The sum is: " + sum);
}
- 特点: 函数声明会被提升 (Hoisted)。这意味着你可以在声明函数的代码之前调用它,JavaScript 引擎会“看到”整个脚本中的函数声明。
2. 函数表达式 (Function Expression)
这种方式是将一个匿名函数(没有名字的函数)赋值给一个变量。这个变量就成了引用该函数的名字。
// 将一个匿名函数赋值给变量 sayHi
const sayHi = function() {console.log("Hi!");
};// 将一个接收参数的匿名函数赋值给变量 multiply
const multiply = function(x, y) {let product = x * y;console.log("The product is: " + product);
};
- 特点: 函数表达式不会被整体提升。虽然变量声明(const sayHi)会被提升,但赋值操作(= function()...)不会。所以,你必须在函数表达式定义之后才能调用它。
3. 箭头函数 (Arrow Functions) (ES6 新增)
这是 ES6 引入的一种更简洁的函数定义语法,尤其适用于简单的函数或回调函数。
// 一个简单的箭头函数
const wave = () => {console.log("Waving!");
};// 接收参数的箭头函数
const subtract = (a, b) => {let difference = a - b;console.log("The difference is: " + difference);
};// 如果函数体只有一条返回语句,可以省略大括号和 return 关键字
const square = x => x * x; // 等价于: const square = (x) => { return x * x; };// 如果只有一个参数,圆括号也可以省略
- 特点: 语法更短。它还有一些重要的特性,比如不绑定自己的 this 值(我们将在后续深入 this 时详细讨论)。对于初学者,可以先掌握它的基本语法。
选择哪种方式?
- 函数声明是最传统和常见的方式。
- 函数表达式有时用于特定的模式,如需要根据条件定义函数。
- 箭头函数因其简洁性在现代 JavaScript 中非常流行,尤其是在处理回调和简单功能时。
初学者可以先熟练掌握函数声明和函数表达式。
三、调用函数:使用你的“积木”
定义好函数后,它并不会自动执行。你需要通过函数名后面跟一对圆括号 () 来调用 (Call / Invoke / Execute) 它。
// --- 定义函数 ---
function showMessage() {console.log("This is a message.");
}const calculateArea = function(width, height) {let area = width * height;console.log("Area:", area);
};const printName = name => console.log("Name:", name);// --- 调用函数 ---
showMessage(); // 输出: This is a message.calculateArea(10, 5); // 输出: Area: 50printName("Alice"); // 输出: Name: Alice
四、参数与参数 (Parameters & Arguments):给函数传递信息
函数可以接收外部传入的数据,以便更灵活地执行任务。
- 参数 (Parameters): 定义函数时,在圆括号 () 里声明的变量名,它们是函数内部用来接收输入值的占位符。
- 参数 (Arguments): 调用函数时,在圆括号 () 里传递的实际值。这些值会按顺序赋给函数定义中的参数。
// 定义函数,`name` 和 `age` 是参数 (Parameters)
function displayUserInfo(name, age) {console.log(`User: ${name}, Age: ${age}`);
}// 调用函数,"Bob" 和 30 是参数 (Arguments)
displayUserInfo("Bob", 30); // 输出: User: Bob, Age: 30// 可以传递变量作为参数
let userName = "Charlie";
let userAge = 25;
displayUserInfo(userName, userAge); // 输出: User: Charlie, Age: 25// 如果传递的参数数量与定义的参数数量不匹配:
displayUserInfo("David"); // 输出: User: David, Age: undefined (age 没有接收到值,是 undefined)
displayUserInfo("Eve", 22, "extra argument"); // 输出: User: Eve, Age: 22 (多余的参数会被忽略)
默认参数 (Default Parameters) (ES6):
你可以为函数的参数指定默认值。如果在调用函数时没有为该参数提供值(或提供了 undefined),则会使用默认值。
function greetUser(name = "Guest") { // 如果不传 name,默认为 "Guest"console.log(`Hello, ${name}!`);
}greetUser("Frank"); // 输出: Hello, Frank!
greetUser(); // 输出: Hello, Guest!
五、返回值 (Return Value):从函数获取结果
函数不仅可以执行操作,还可以通过 return 语句将计算结果或某个值返回给调用它的地方。
-
return 语句:
- 立即结束当前函数的执行。
- 将 return 后面的表达式的值作为函数的返回值,发送回调用处。
- 如果省略 return 语句,或者 return 后面没有跟任何值,函数会默认返回 undefined。
// 定义一个计算圆面积并返回结果的函数
function calculateCircleArea(radius) {if (radius < 0) {console.error("Radius cannot be negative!");return; // 如果半径为负,直接返回 undefined,不再往下执行}let area = Math.PI * radius * radius;return area; // 返回计算得到的面积
}// 调用函数,并将返回值存储在变量中
let circleArea = calculateCircleArea(5);
if (circleArea !== undefined) {console.log(`The area is: ${circleArea.toFixed(2)}`); // 输出: The area is: 78.54
}let invalidArea = calculateCircleArea(-2);
console.log("Invalid area result:", invalidArea); // 输出: Invalid area result: undefined// 没有 return 语句的函数
function logSomething() {console.log("Logging...");// 没有 return
}
let result = logSomething();
console.log("Result of logSomething:", result); // 输出: Result of logSomething: undefined
返回值使得函数可以参与到更复杂的表达式和计算中。
六、函数作用域初探 (Function Scope)
一个重要的概念是:在函数内部使用 let 或 const (以及旧的 var) 声明的变量,通常只在该函数内部可见和可用。它们被称为局部变量 (Local Variables)。
function testScope() {let localVar = "I am local";console.log(localVar); // 在函数内部可以访问
}testScope(); // 输出: I am local// console.log(localVar); // 在函数外部访问会报错: Uncaught ReferenceError: localVar is not defined
这有助于保持函数内部状态的独立性,避免与外部代码产生命名冲突。我们将在后续深入探讨作用域和闭包。