JavaScript 函数终极教程
函数是 JavaScript 的核心构建块,它们是可重复使用的代码块,用于执行特定的任务,理解函数是掌握 JavaScript 的关键一步。

目录
- 什么是函数?
- 函数的基本语法
- 函数参数
- 函数返回值
- 函数表达式 vs 函数声明
- 箭头函数 (ES6)
- 作用域 和提升
- 高阶函数
- 闭包
- 立即调用函数表达式
- 最佳实践与总结
什么是函数?
想象一下函数就像一个“工具箱”,你给它一些原材料(参数),它按照一套固定的指令(函数体)进行加工,最后可能会给你一个成品(返回值)。
在编程中,函数的主要作用是:
- 代码复用:避免重复编写相同的代码。
- 模块化:将复杂的任务分解成更小、更易管理的部分。
- 可读性:让代码结构更清晰,更容易理解和维护。
函数的基本语法
定义函数最基本的方式是使用 function 关键字,这被称为函数声明。
// 语法
function functionName(参数1, 参数2, ...) {
// 函数体:这里是要执行的代码
// ...
// 可选:返回一个值
return 返回值;
}
// 示例:一个简单的打招呼函数
function sayHello() {
console.log("你好,世界!");
}
// 调用(执行)函数
sayHello(); // 输出: 你好,世界!
组成部分解析:

function: 关键字,告诉 JavaScript 你正在定义一个函数。functionName: 函数的名称,用于在后续调用它,命名应具有描述性(calculateSum比doSomething更好)。(parameters): 参数列表,用逗号分隔,这是你传递给函数的“原材料”,如果没有参数,括号可以为空。- 函数体,包含函数要执行的所有语句。
return: 关键字,用于从函数中“返回”一个值,执行到return语句后,函数会立即停止执行。
函数参数
参数是函数与外部世界交互的入口,你可以向函数传递数据,让函数基于这些数据执行操作。
1 传递参数
// 定义一个带参数的函数
function greet(name) {
console.log("你好, " + name + "!");
}
// 调用时传入参数
greet("Alice"); // 输出: 你好, Alice!
greet("Bob"); // 输出: 你好, Bob!
2 默认参数 (ES6)
如果调用函数时没有提供某个参数,你可以为其设置一个默认值。
function power(base, exponent = 2) {
return base ** exponent;
}
console.log(power(4)); // 输出: 16 (因为 exponent 默认为 2)
console.log(power(4, 3)); // 输出: 64 (覆盖了默认值)
3 剩余参数
当你不确定会传入多少个参数时,可以使用剩余参数 将它们收集到一个数组中。
function sum(...numbers) {
// numbers 是一个数组,[1, 2, 3]
let total = 0;
for (const num of numbers) {
total += num;
}
return total;
}
console.log(sum(1, 2)); // 输出: 3
console.log(sum(1, 2, 3, 4, 5)); // 输出: 15
函数返回值
函数可以通过 return 语句将一个值“返回”给调用者,如果没有 return 语句,函数会返回 undefined。

// 返回一个值的函数
function add(a, b) {
return a + b;
}
let result = add(5, 3);
console.log(result); // 输出: 8
// 没有返回值的函数
function logMessage(message) {
console.log(message);
}
let returnValue = logMessage("这是一个日志消息。");
console.log(returnValue); // 输出: undefined
重要提示: return 语句会立即终止函数的执行。
function checkAge(age) {
if (age < 18) {
return "未成年";
}
return "已成年"; // 只有当 age >= 18 时才会执行到这里
}
console.log(checkAge(15)); // 输出: "未成年"
console.log(checkAge(20)); // 输出: "已成年"
函数表达式 vs 函数声明
这是 JavaScript 中一个非常重要的概念,它涉及到变量提升。
1 函数声明
我们之前看到的就是函数声明,它有一个关键特性:函数声明会被提升到其作用域的顶部,这意味着你可以在声明函数之前调用它。
sayHi(); // 可以正常执行,因为函数声明被提升了
function sayHi() {
console.log("Hi!");
}
2 函数表达式
将一个函数赋值给一个变量。
// 错误的调用方式
// sayBye(); // 这里会报错,因为变量 sayBye 此时是 undefined
const sayBye = function() {
console.log("Bye!");
};
sayBye(); // 正常执行
关键区别:
- 函数声明:可以被提升,可以在声明前调用。
- 函数表达式:不能被提升(变量会被提升,但赋值不会),只能在声明后调用。
命名函数表达式
你可以在函数表达式中给函数命名,这有助于调试。
const namedFunc = function myNamedFunction() {
console.log("我是一个命名函数表达式。");
};
namedFunc(); // 可以调用
// myNamedFunction(); // 不能调用,这个名字只在函数内部可用
箭头函数 (ES6)
箭头函数是 ES6 引入的一种更简洁的函数书写方式,它不仅语法更短,还改变了一些 this 的行为(稍后会在闭包中提到)。
1 基本语法
// 1. 无参数,单行返回
const sayHello = () => "Hello!";
console.log(sayHello()); // 输出: Hello!
// 2. 单个参数,可以省略括号
const square = x => x * x;
console.log(square(4)); // 输出: 16
// 3. 多个参数,需要括号
const add = (a, b) => a + b;
console.log(add(2, 3)); // 输出: 5
// 4. 函数体有多行代码,需要花括号,并且必须使用 return
const complexCalc = (a, b) => {
const sum = a + b;
const product = a * b;
return { sum, product };
};
console.log(complexCalc(3, 4)); // 输出: { sum: 7, product: 12 }
2 this 的区别
箭头函数没有自己的 this,它会从其外部(词法)作用域继承 this,这使得它在回调函数(如 setTimeout, map, filter)中非常有用。
function traditionalFunction() {
console.log(this); // 在浏览器中,通常指向 window 对象
}
const arrowFunction = () => {
console.log(this); // 继承外部作用域的 this
};
// 假设在一个对象中
const person = {
name: "Alice",
greetTraditional: function() {
console.log(`你好,我是 ${this.name}`);
},
greetArrow: () => {
console.log(`你好,我是 ${this.name}`); // 这里的 this 是全局的,不是 person
}
};
person.greetTraditional(); // 输出: 你好,我是 Alice
person.greetArrow(); // 输出: 你好,我是 undefined (因为 this.name 是 undefined)
作用域 和提升
理解作用域和提升对于避免难以发现的 bug 至关重要。
1 作用域
作用域决定了变量和函数的可访问性。
- 全局作用域:在任何函数外部定义的变量,在整个程序中都可以访问。
- 函数作用域:在函数内部定义的变量,只能在函数内部访问。
let globalVar = "我是全局变量";
function myFunction() {
let functionVar = "我是函数内部变量";
console.log(globalVar); // 可以访问
console.log(functionVar); // 可以访问
}
myFunction();
// console.log(functionVar); // 会报错,因为 functionVar 不在当前作用域
2 提升
JavaScript 引擎在代码执行前会进行“预编译”,在这个过程中,变量和函数声明会被移动到其作用域的顶部。
- 变量提升:
var声明的变量会被提升,但初始化不会,这会导致var存在一些问题(var x;和var x = 10;的区别)。 - 函数提升:函数声明会被完整提升,因此你可以在声明前调用它。
let, const, var 的区别:
var: 函数作用域,有提升问题,可以被重复声明。let: 块级作用域( 内),有提升(但不初始化),在声明前访问会报错(暂时性死区 TDZ),不能被重复声明。const: 和let类似,但声明的变量是常量,不能被重新赋值。
推荐:在现代 JavaScript 开发中,优先使用 const,如果变量需要被重新赋值,再使用 let,尽量避免使用 var。
高阶函数
高阶函数是函数式编程的核心概念,它是指满足以下任一条件的函数:
- 接受一个或多个函数作为参数。
- 返回一个函数。
常见的例子是数组的 map, filter, forEach 等方法。
1 接受函数作为参数
function callWithFive(callback) {
// 调用传入的函数,并传入参数 5
callback(5);
}
function printNumber(num) {
console.log("打印的数字是:", num);
}
callWithFive(printNumber); // 输出: 打印的数字是: 5
2 返回一个函数
function createMultiplier(multiplier) {
// 返回一个新的函数
return function(number) {
return number * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(10)); // 输出: 20
console.log(triple(10)); // 输出: 30
闭包
闭包是一个非常重要且强大的概念,它指的是一个函数能够“并访问其词法作用域,即使该函数在其词法作用域之外执行。
就是内层函数可以访问外层函数的变量。
function outerFunction(x) {
// outerFunction 的作用域
let message = "外层函数的变量: ";
return function innerFunction(y) {
// innerFunction 访问了外层函数的变量 x
// 这就形成了一个闭包
console.log(message + x + y);
};
}
const myClosure = outerFunction(10); // myClosure 持有了 outerFunction 的作用域
myClosure(5); // 输出: 外层函数的变量: 105
myClosure(1); // 输出: 外层函数的变量: 101
闭包的应用:
- 数据私有化:创建只能通过特定方法访问的私有变量。
- 创建工厂函数:如上面高阶函数的例子,
createMultiplier就是一个利用闭包的工厂函数。 - 回调函数和事件处理:在异步操作中,回调函数需要访问其定义时的上下文。
立即调用函数表达式
IIFE 是一种在定义后立即执行的函数表达式,它主要用于创建一个新的作用域,以避免污染全局命名空间。
// 语法:(function() { /* 代码 */ })();
(function() {
console.log("这个函数只会执行一次。");
let privateVar = "我是私有变量";
console.log(privateVar);
})(); // 立即执行
// console.log(privateVar); // 会报错,因为 privateVar 不在全局作用域内
为什么用 包裹?
JavaScript 引擎看到 function 关键字时,默认会将其视为一个函数声明,函数声明不能立即执行,必须以分号结尾,通过用 或 等运算符将其包裹起来,JavaScript 引擎就会将其解析为一个函数表达式,从而可以立即执行。
最佳实践与总结
- 命名清晰:函数名应该用动词开头,并清晰描述其功能(
fetchUserData,validateInput)。 - 保持简洁:一个函数应该只做一件事,这被称为“单一职责原则”。
- 参数尽量少:函数参数越多,调用就越复杂,超过 3-4 个参数时,考虑使用一个对象作为参数。
- 优先使用
const和let:避免使用var。 - 使用箭头函数:在需要回调函数或
this不会造成困扰的地方,优先使用简洁的箭头函数。 - 添加注释:对于复杂的函数逻辑,添加注释解释其目的和工作方式。
- 理解闭包:闭包是 JavaScript 的精髓之一,务必深入理解。
JavaScript 函数是构建动态和交互式应用程序的基石,从基础的声明和调用,到高级的闭包和高阶函数,每一个概念都至关重要。
- 函数声明:最基础的定义方式,有提升。
- 函数表达式:将函数赋值给变量,更灵活,无提升。
- 箭头函数:更简洁的语法,并改变了
this的行为。 - 参数和返回值:函数与外界交互的桥梁。
- 作用域和提升:决定了变量的可见性,是理解代码执行顺序的关键。
- 高阶函数和闭包:实现函数式编程和高级模式的强大工具。
希望这份教程能帮助你全面掌握 JavaScript 函数!多写代码,多实践,这些概念会变得越来越清晰。
