什么是参数默认值?
在 ES6 之前,如果我们想给函数参数设置一个默认值,通常需要在函数体内部使用逻辑判断(如 if 语句或三元运算符)来实现。
ES6 之前的写法:
function sayHello(name) {
// name 没有传入,或者传入的是 undefined,则使用 'Guest' 作为默认值
if (!name) {
name = 'Guest';
}
console.log(`Hello, ${name}!`);
}
sayHello('Alice'); // Hello, Alice!
sayHello(); // Hello, Guest!
这种写法有些冗长,而且容易出错(当传入 name = 0 或 name = '' 时,!name 也为 true,但可能不是我们想要的行为)。
ES6 引入了参数默认值语法,使得在函数定义时直接为参数指定默认值变得非常简洁和直观。
ES6 参数默认值的语法
语法非常简单,在参数名后面直接跟一个等号 和默认值即可。
function functionName(param1 = defaultValue1, param2 = defaultValue2) {
// 函数体
}
示例:
function sayHello(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
sayHello('Bob'); // Hello, Bob!
sayHello(); // Hello, Guest!
参数默认值的工作原理
参数默认值只在参数的值为 undefined 时才会生效。它不会检查参数是否被省略,而是检查参数的值是否是 undefined。
示例:
function test(a = 1, b = 2) {
console.log(a, b);
}
test(); // 1 2 (两个参数都是 undefined,所以都使用默认值)
test(10); // 10 2 (a 是 10, b 是 undefined)
test(10, 20); // 10 20 (两个参数都有值,不使用默认值)
test(undefined, 20); // 1 20 (a 是 undefined,使用默认值 1)
test(null, 20); // null 20 (a 是 null,不是 undefined,所以不使用默认值)
注意: null 会被当作一个有效的值,不会触发默认值。
默认值可以是什么?
默认值不仅可以是简单的原始值(如字符串、数字、布尔值),还可以是表达式、函数调用,甚至是其他参数。
示例 1:默认值为表达式
function getRandomNumber(max = 100) {
return Math.floor(Math.random() * max);
}
console.log(getRandomNumber()); // 在 0 到 99 之间随机
console.log(getRandomNumber(50)); // 在 0 到 49 之间随机
示例 2:默认值为函数调用
function getUserName(firstName, lastName = getLastName()) {
return `${firstName} ${lastName}`;
}
function getLastName() {
return 'Doe';
}
console.log(getUserName('John')); // John Doe
console.log(getUserName('Jane', 'Smith')); // Jane Smith (默认值函数不会被调用)
示例 3:默认值为其他参数(重要!)
默认值可以引用函数定义之前已经声明的参数。
function connect(url, port = 8080, baseUrl = `http://${url}:${port}`) {
console.log(`Connecting to: ${baseUrl}`);
}
connect('api.example.com'); // Connecting to: http://api.example.com:8080
connect('api.example.com', 3000); // Connecting to: http://api.example.com:3000
注意: 参数默认值是按顺序求值的,不能引用在它之后定义的参数,下面的代码会报错:
// 错误的写法
function connect(url = 'localhost', port = 8080, baseUrl = `http://${url}:${port}`) {
// ...
}
// 正确的写法
function connect(port = 8080, url = `localhost:${port}`, baseUrl = `http://${url}`) {
// ...
}
与解构赋值结合使用
参数默认值与对象的解构赋值结合使用时,威力巨大,这是非常常见和实用的模式,可以让你方便地处理一个包含多个配置选项的对象。
场景: 你希望一个函数接收一个配置对象,并给其中的某些属性设置默认值。
不使用解构赋值的旧方法:
function createSettings(options) {
const width = options.width || 800;
const height = options.height || 600;
const theme = options.theme || 'light';
console.log(`Width: ${width}, Height: ${height}, Theme: ${theme}`);
}
createSettings({ width: 1024 }); // Width: 1024, Height: 600, Theme: light
使用解构赋值 + 参数默认值(现代写法):
function createSettings({ width = 800, height = 600, theme = 'light' } = {}) {
console.log(`Width: ${width}, Height: ${height}, Theme: ${theme}`);
}
// 解释:
// 1. `width = 800, height = 600, theme = 'light'` 是对传入的第一个参数进行解构。
// 如果解构失败(比如传入 null 或 undefined),那么这些局部变量会使用各自的默认值。
// 2. `= {}` 是整个参数的默认值。
// 如果调用 `createSettings()` 时完全不传任何参数,`options` 就会是 `{}`,
// 然后对 `{}` 进行解构,所有属性都取不到,最终使用各自的默认值。
createSettings(); // Width: 800, Height: 600, Theme: light
createSettings({}); // Width: 800, Height: 600, Theme: light
createSettings({ width: 1024 }); // Width: 1024, Height: 600, Theme: light
createSettings({ theme: 'dark' }); // Width: 800, Height: 600, Theme: dark
createSettings(null); // 如果传入 null,解构会失败,所以会使用默认值
注意 的重要性:
如果去掉 ,当完全不传参数时,会尝试对 undefined 进行解构,这会直接抛出错误。
// 错误的写法
function createSettings({ width = 800 }) {
// ...
}
createSettings(); // TypeError: Cannot destructure property 'width' of 'undefined' as it is undefined.
严格模式
在严格模式下,不能有同名的参数,参数默认值不会影响这一点。
// 报错
function foo(a, a) {
// ...
}
// 报错
function bar(a, a = 10) {
// ...
}
| 特性 | 描述 | 示例 |
|---|---|---|
| 基本语法 | 在参数名后使用 和默认值。 | function fn(name = 'default') {} |
| 触发条件 | 仅当参数的值为 undefined 时生效。 |
fn(null) 不会使用默认值。 |
| 默认值类型 | 可以是任何表达式,包括函数调用和前序参数。 | function fn(a, b = a) {} |
| 与解构结合 | 是处理配置对象的强大工具,需要为整个参数设置默认空对象 。 | function fn({x=1} = {}) {} |
| ES6 之前 | 需要在函数体内用 if 或 逻辑判断。 |
if (name === undefined) name = 'default'; |
参数默认值是 ES6 带来的一个非常重要且实用的特性,它让代码更简洁、更健壮,也更符合直觉。
