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 这类意外结果,可以用默认参数兜底。
- 实参多于形参时,多余部分被忽略。