
JavaScript函数
JavaScript函数
函数的定义与调用
在 JavaScript 中,定义函数有几种方式。
1. 函数声明 (Function Declaration)
这是最常见的定义函数的方式。
// 函数声明
function greet(name) {
return "你好," + name + "!";
}
// 调用函数
console.log(greet("小明")); // 输出: 你好,小明!
特点:
-
函数声明在执行上下文加载时就被解析,这意味着你可以在声明函数之前调用它(这被称为函数提升)。
console.log(sayHello("张三")); // 输出: Hello, 张三! function sayHello(name) { return "Hello, " + name + "!"; }
2. 函数表达式 (Function Expression)
函数表达式是将函数作为表达式的一部分创建的。通常,这意味着将一个匿名函数赋值给一个变量。
// 函数表达式
const sayGoodbye = function(name) {
return "再见," + name + "!";
};
// 调用函数
console.log(sayGoodbye("李华")); // 输出: 再见,李华!
特点:
-
函数表达式不会被提升。你必须在定义函数之后才能调用它。
// console.log(farewell("王五")); // 这会报错:ReferenceError: Cannot access 'farewell' before initialization const farewell = function(name) { return "Farewell, " + name + "!"; }; console.log(farewell("王五")); // 输出: Farewell, 王五!
3. 箭头函数 (Arrow Function)
ES6 (ECMAScript 2015) 引入了箭头函数,提供了一种更简洁的函数定义方式。
// 箭头函数
const add = (a, b) => a + b;
// 调用函数
console.log(add(5, 3)); // 输出: 8
// 带有多个参数或更复杂逻辑的箭头函数
const multiply = (x, y) => {
const result = x * y;
return `结果是:${result}`;
};
console.log(multiply(4, 6)); // 输出: 结果是:24
特点:
- 语法简洁: 特别适用于简单的回调函数。
- 没有自己的
this
: 箭头函数没有自己的this
绑定,它会捕获其定义时的上下文的this
值。这与普通函数(它们有自己的this
绑定)不同。 - 不能作为构造函数: 箭头函数不能使用
new
关键字来创建实例。 - 没有
arguments
对象: 箭头函数没有自己的arguments
对象,但可以使用剩余参数 (rest parameters) 来替代。
函数的参数
函数可以接受零个或多个参数。
1. 默认参数 (Default Parameters)
ES6 允许为函数参数指定默认值。
function greetUser(name = "访客") {
return "欢迎," + name + "!";
}
console.log(greetUser("小红")); // 输出: 欢迎,小红!
console.log(greetUser()); // 输出: 欢迎,访客!
2. 剩余参数 (Rest Parameters)
剩余参数允许你将不定数量的参数表示为一个数组。
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)); // 输出: 100
3. arguments 对象 (在非箭头函数中)
在传统的(非箭头)函数中,arguments
是一个类数组对象,包含了函数被调用时传入的所有参数。
function showArgs() {
console.log(arguments);
}
showArgs(1, "hello", true);
// 输出: [Arguments] { '0': 1, '1': 'hello', '2': true }
注意: 箭头函数没有 arguments
对象。
函数的返回值
函数可以使用 return
语句返回一个值。如果没有 return
语句,或者 return
语句后面没有表达式,函数会隐式返回 undefined
。
function calculateArea(width, height) {
if (width <= 0 || height <= 0) {
return "宽度和高度必须是正数!"; // 返回错误信息
}
return width * height; // 返回计算结果
}
console.log(calculateArea(10, 5)); // 输出: 50
console.log(calculateArea(-2, 3)); // 输出: 宽度和高度必须是正数!
console.log(calculateArea(7, 0)); // 输出: 宽度和高度必须是正数!
function doNothing() {
// 没有return语句
}
console.log(doNothing()); // 输出: undefined
函数作为一等公民 (First-Class Functions)
在 JavaScript 中,函数被视为“一等公民”,这意味着它们可以:
- 赋值给变量 (如函数表达式所示)。
- 作为参数传递给其他函数 (高阶函数)。
- 作为函数的返回值 (高阶函数)。
作为参数传递 (回调函数)
function operate(num1, num2, operation) {
return operation(num1, num2);
}
const addOperation = (a, b) => a + b;
const subtractOperation = (a, b) => a - b;
console.log(operate(10, 5, addOperation)); // 输出: 15
console.log(operate(10, 5, subtractOperation)); // 输出: 5
// 也可以直接传入匿名函数
console.log(operate(8, 2, (x, y) => x * y)); // 输出: 16
这里的 operation
就是一个回调函数 (Callback Function),它在 operate
函数内部被调用。
作为返回值 (闭包)
当一个函数返回另一个函数时,并且内部函数仍然可以访问外部函数的变量时,就形成了闭包 (Closure)。
function createCounter() {
let count = 0; // 这是一个局部变量
return function() { // 返回一个匿名函数
count++;
return count;
};
}
const counter1 = createCounter();
console.log(counter1()); // 输出: 1
console.log(counter1()); // 输出: 2
const counter2 = createCounter(); // 创建一个新的计数器实例
console.log(counter2()); // 输出: 1
console.log(counter1()); // 输出: 3 (counter1 保持自己的状态)
在这个例子中,匿名函数形成了闭包,即使 createCounter
已经执行完毕,它仍然能够访问和修改 count
变量。
立即执行函数表达式 (IIFE - Immediately Invoked Function Expression)
IIFE 是一种定义后立即执行的函数。它常用于创建独立的作用域,避免变量污染全局环境。
(function() {
const message = "这是一个IIFE的私有变量";
console.log(message); // 输出: 这是一个IIFE的私有变量
})();
// console.log(message); // ReferenceError: message is not defined
递归函数
递归函数是指在函数内部调用自身的函数。通常用于解决可以分解为相同子问题的问题。
function factorial(n) {
// 基本情况 (终止条件)
if (n === 0 || n === 1) {
return 1;
}
// 递归调用
return n * factorial(n - 1);
}
console.log(factorial(5)); // 输出: 120 (5 * 4 * 3 * 2 * 1)
console.log(factorial(0)); // 输出: 1
注意: 编写递归函数时,必须有一个基本情况 (base case) 来终止递归,否则会导致无限循环(栈溢出)。