Skip to content

JavaScript 函数参数

函数参数的概念

函数参数是传递给函数的值,用于在函数内部执行操作。在 JavaScript 中,函数参数的处理方式非常灵活,支持多种参数类型和特性。

函数参数的类型

1. 基本参数

基本参数是最常见的参数类型,直接在函数定义时声明:

javascript
function add(a, b) {
  return a + b;
}

console.log(add(5, 10)); // 输出: 15

2. 默认参数

默认参数是 ES6 引入的特性,允许为参数设置默认值:

javascript
function add(a, b = 0) {
  return a + b;
}

console.log(add(5)); // 输出: 5(使用默认值 0)
console.log(add(5, 10)); // 输出: 15(使用传入的值)

// 多个默认参数
function greet(name, message = "Hello") {
  return `${message}, ${name}!`;
}

console.log(greet("John")); // 输出: Hello, John!
console.log(greet("John", "Hi")); // 输出: Hi, John!

3. 剩余参数

剩余参数是 ES6 引入的特性,允许将多个参数收集到一个数组中:

javascript
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3)); // 输出: 6
console.log(sum(1, 2, 3, 4, 5)); // 输出: 15

// 剩余参数与普通参数结合
function greet(name, ...messages) {
  return `${name}: ${messages.join(", ")}`;
}

console.log(greet("John", "Hello", "How are you?")); // 输出: John: Hello, How are you?

4. 解构参数

解构参数是 ES6 引入的特性,允许从对象或数组中提取值作为参数:

对象解构参数

javascript
function createUser({ name, email, age = 18 }) {
  return {
    name,
    email,
    age,
  };
}

const user = createUser({ name: "John", email: "john@example.com" });
console.log(user); // 输出: { name: 'John', email: 'john@example.com', age: 18 }

// 为整个解构参数设置默认值
function createUser2({ name, email, age = 18 } = {}) {
  return {
    name,
    email,
    age,
  };
}

const user2 = createUser2();
console.log(user2); // 输出: { name: undefined, email: undefined, age: 18 }

数组解构参数

javascript
function sum([a, b, c]) {
  return a + b + c;
}

console.log(sum([1, 2, 3])); // 输出: 6

// 与剩余参数结合
function sum2([a, b, ...rest]) {
  return a + b + rest.reduce((total, num) => total + num, 0);
}

console.log(sum2([1, 2, 3, 4, 5])); // 输出: 15

5. 参数传递方式

JavaScript 中的参数传递方式取决于参数的类型:

基本类型参数(值传递)

基本类型(数字、字符串、布尔值、null、undefined)作为参数传递时,是值传递:

javascript
function modifyValue(num) {
  num = 10;
  console.log(num); // 输出: 10
}

let value = 5;
modifyValue(value);
console.log(value); // 输出: 5(原始值不变)

引用类型参数(引用传递)

引用类型(对象、数组、函数)作为参数传递时,是引用传递:

javascript
function modifyObject(obj) {
  obj.name = "John";
  console.log(obj.name); // 输出: John
}

let person = { name: "Jane" };
modifyObject(person);
console.log(person.name); // 输出: John(原始对象被修改)

// 注意:如果在函数内部重新赋值对象,原始对象不会改变
function reassignObject(obj) {
  obj = { name: "John" };
  console.log(obj.name); // 输出: John
}

let person2 = { name: "Jane" };
reassignObject(person2);
console.log(person2.name); // 输出: Jane(原始对象不变)

函数参数的特性

1. arguments 对象

arguments 是一个类数组对象,包含了传递给函数的所有参数:

javascript
function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

console.log(sum(1, 2, 3)); // 输出: 6
console.log(sum(1, 2, 3, 4, 5)); // 输出: 15

// 注意:箭头函数没有 arguments 对象
const sumArrow = () => {
  console.log(arguments); // 错误:arguments 未定义
};

2. 参数长度

可以使用 length 属性获取函数定义时的参数个数:

javascript
function add(a, b) {
  return a + b;
}

console.log(add.length); // 输出: 2

function greet(name, message = "Hello") {
  return `${message}, ${name}!`;
}

console.log(greet.length); // 输出: 1(默认参数不计入长度)

function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum.length); // 输出: 0(剩余参数不计入长度)

3. 参数验证

在函数内部,可以对参数进行验证,确保参数符合预期:

javascript
function divide(a, b) {
  if (typeof a !== "number" || typeof b !== "number") {
    throw new Error("Both arguments must be numbers");
  }
  if (b === 0) {
    throw new Error("Division by zero");
  }
  return a / b;
}

try {
  console.log(divide(10, 2)); // 输出: 5
  console.log(divide(10, "2")); // 错误:参数类型错误
} catch (error) {
  console.error(error.message);
}

函数参数的最佳实践

1. 使用默认参数

对于可选参数,使用默认参数而不是手动检查:

javascript
// 好的做法
function greet(name, message = "Hello") {
  return `${message}, ${name}!`;
}

// 不好的做法
function greet(name, message) {
  message = message || "Hello";
  return `${message}, ${name}!`;
}

2. 使用剩余参数处理多个参数

对于需要处理多个参数的函数,使用剩余参数而不是 arguments 对象:

javascript
// 好的做法
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

// 不好的做法
function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

3. 使用解构参数处理复杂参数

对于需要多个相关参数的函数,使用解构参数:

javascript
// 好的做法
function createUser({ name, email, age = 18 }) {
  // 创建用户
}

createUser({ name: "John", email: "john@example.com" });

// 不好的做法
function createUser(name, email, age) {
  // 创建用户
}

createUser("John", "john@example.com", 18);

4. 合理设置参数顺序

将必需参数放在前面,可选参数放在后面:

javascript
// 好的做法
function greet(name, message = "Hello") {
  return `${message}, ${name}!`;
}

// 不好的做法
function greet(message = "Hello", name) {
  return `${message}, ${name}!`;
}

5. 限制参数数量

函数参数数量应该合理,通常不超过 3-4 个:

javascript
// 好的做法
function calculate(a, b, operation = "add") {
  // 计算
}

// 不好的做法
function calculate(a, b, c, d, e, operation) {
  // 计算
}

6. 验证参数类型

对于重要的函数,验证参数类型以确保函数正常工作:

javascript
function multiply(a, b) {
  if (typeof a !== "number" || typeof b !== "number") {
    throw new Error("Both arguments must be numbers");
  }
  return a * b;
}

函数参数的常见错误

1. 忘记使用默认参数

对于可选参数,应该使用默认参数而不是手动检查:

javascript
// 错误:忘记使用默认参数
function add(a, b) {
  b = b || 0;
  return a + b;
}

console.log(add(5, 0)); // 输出: 5(正确)
console.log(add(5, false)); // 输出: 5(错误:false 被转换为 0)

// 正确:使用默认参数
function add(a, b = 0) {
  return a + b;
}

console.log(add(5, 0)); // 输出: 5(正确)
console.log(add(5, false)); // 输出: 5(正确:false 被视为 0)

2. 混淆参数传递方式

注意基本类型和引用类型的参数传递方式:

javascript
// 错误:期望修改原始值
function modifyValue(num) {
  num = 10;
}

let value = 5;
modifyValue(value);
console.log(value); // 输出: 5(原始值不变)

// 正确:返回新值
function getModifiedValue(num) {
  return num * 2;
}

let value2 = 5;
value2 = getModifiedValue(value2);
console.log(value2); // 输出: 10(原始值被更新)

3. 剩余参数位置错误

剩余参数必须是函数的最后一个参数:

javascript
// 错误:剩余参数不是最后一个参数
function sum(...numbers, multiplier) {
  return numbers.reduce((total, num) => total + num, 0) * multiplier;
}

// 正确:剩余参数是最后一个参数
function sum(multiplier, ...numbers) {
  return numbers.reduce((total, num) => total + num, 0) * multiplier;
}

console.log(sum(2, 1, 2, 3)); // 输出: 12

小结

JavaScript 函数参数非常灵活,支持多种参数类型和特性,包括基本参数、默认参数、剩余参数和解构参数。理解这些参数类型和特性,以及它们的传递方式,是编写高质量 JavaScript 代码的重要组成部分。在实际开发中,应该遵循最佳实践,使用合适的参数类型,合理设置参数顺序,限制参数数量,并验证参数类型,以提高函数的可读性、可维护性和可靠性。