六维教程

JavaScript 函数参数

上一篇的函数例子已经用到参数。参数让同一个函数能处理不同的输入,是函数灵活性的关键。这篇把参数的细节讲清楚,包括形参实参的区别、传值还是传引用、默认参数,以及参数数量不匹配的情况。

形参和实参

形参是定义函数时写在括号里的占位符,实参是调用时传入的实际值。调用时实参按顺序和形参一一对应。

function greet(name, age) {
  console.log('你好' + name + ',今年' + age + '岁');
}

greet('小明', 18);

name 和 age 是形参,’小明’ 和 18 是实参。第一个实参给第一个形参,第二个实参给第二个形参。调用 greet(‘小红’, 20) 就会输出小红的信息,同一个函数服务不同的人。

基本类型传值,对象传引用

传参的本质要分清。基本类型,包括数字、字符串、布尔等,传的是值的拷贝。函数内修改拷贝不影响函数外的原变量。

function addOne(n) {
  n = n + 1;
  console.log('函数内 ' + n); // 输出 函数内 6
}

let num = 5;
addOne(num);
console.log('函数外 ' + num); // 输出 函数外 5

函数里改的是拷贝出来的那份,外面的 num 不受影响。

对象,包括数组,传的是引用。函数内修改会改动原来的对象。

function addFruit(list) {
  list.push('橘子');
}

const fruits = ['苹果', '香蕉'];
addFruit(fruits);
console.log(fruits); // 输出 ['苹果', '香蕉', '橘子']

list 和 fruits 指向同一个数组,push 直接改在原数组上,函数外的 fruits 也跟着变了。想避免这个问题,可以在函数内先复制一份再操作,复制数组的方法在数组教程里细讲,这里先记住对象传引用这个事实。

默认参数

调用时不传某个参数,对应形参就是 undefined。有时希望不传时自动用默认值,可以在定义时给形参赋默认值,这是 ES6 提供的特性,直接写等于号就行。

function greet(name = '朋友') {
  console.log('你好,' + name);
}

greet('小明'); // 输出 你好,小明
greet();       // 输出 你好,朋友

不传 name 时自动用默认值’朋友’。默认值只在实参为 undefined 时生效,显式传入 undefined 也一样走默认值,传入其他值就用传入的值。

默认参数让函数调用更灵活,少传参数也不会出问题。比如设置页面标题,标题可以省略

function setTitle(title = '默认标题') {
  console.log('标题设置为 ' + title);
}

setTitle('我的博客');
setTitle();

参数少于形参

实参比形参少时,没被接住的形参就是 undefined。函数里用到 undefined 可能算出奇怪结果。

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

console.log(add(3)); // 输出 NaN

只传了一个实参,b 是 undefined,3 + undefined 结果是 NaN。这时默认参数就派上用场了,给 b 设默认值 0,add(3) 就是 3。

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

console.log(add(3)); // 输出 3

参数多于形参

反过来,实参比形参多时,多余的实参会被忽略。

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

console.log(add(1, 2, 3)); // 输出 3,多余的 3 被忽略

多传的参数没有形参接住,函数里用不到。想处理任意数量的参数,有 rest 参数之类的进阶特性,这里先知道多余的会被忽略就行。

小结

  • 形参是定义时的占位符,实参是调用时传入的值,按顺序一一对应。
  • 基本类型传值拷贝,函数内修改不影响外部。对象传引用,函数内修改会改动原对象。
  • 默认参数用 name = 默认值 的写法,不传时自动使用默认值。
  • 实参少于形参时,缺失的形参是 undefined,容易产生 NaN 这类意外结果,可以用默认参数兜底。
  • 实参多于形参时,多余部分被忽略。
上一篇
JavaScript 函数的定义与调用
下一篇
JavaScript 作用域