返回

形参默认值的陷阱

前端

不要随便使用形参默认值

前言
在 JavaScript 中,函数的参数可以具有默认值。默认值在函数被调用时指定,如果没有传递参数,则使用默认值。虽然形参默认值很方便,但使用时需要注意一些陷阱。

陷阱一:内部变量的意外值

当函数内部使用 let 或 const 声明变量时,如果该变量与形参同名,并且形参具有默认值,那么该变量的值可能会被意外修改。

function greet(name = "John") {
  // 内部变量 name 与形参 name 同名
  let name = "Mary";

  console.log(`Hello, ${name}!`);
}

greet(); // 输出: "Hello, John!"

在这个例子中,函数内部的 let name 声明了一个新的变量,并将其值设置为 "Mary"。然而,当函数被调用时,形参 name 的默认值 "John" 会覆盖内部变量的值。因此,console.log() 语句输出 "Hello, John!",而不是 "Hello, Mary!"。

陷阱二:闭包中的变量引用

当函数内部的变量被闭包引用时,如果该变量与形参同名,并且形参具有默认值,那么该变量的值可能会在闭包中被意外修改。

function createGreeter(name = "John") {
  // 返回一个闭包
  return function () {
    console.log(`Hello, ${name}!`);
  };
}

const greeter = createGreeter();

// 修改形参 name 的默认值
name = "Mary";

greeter(); // 输出: "Hello, Mary!"

在这个例子中,createGreeter() 函数返回一个闭包,该闭包引用了内部变量 name。当 greeter() 函数被调用时,闭包内部的 name 变量的值被修改为 "Mary"。因此,console.log() 语句输出 "Hello, Mary!",而不是 "Hello, John!"。

解决方法
为了避免形参默认值带来的陷阱,我们可以使用以下解决方法:

  1. 避免在函数内部使用 let 或 const 声明变量,如果必须使用,请确保变量名与形参不同。
  2. 避免在闭包中引用函数内部的变量,如果必须引用,请确保变量名与形参不同。
  3. 使用箭头函数代替传统函数,箭头函数没有自己的作用域,因此不存在内部变量被意外修改的问题。
// 使用箭头函数代替传统函数
const greet = (name = "John") => {
  console.log(`Hello, ${name}!`);
};

greet(); // 输出: "Hello, John!"

总结
在 JavaScript 中,使用形参默认值时需要注意一些陷阱。为了避免这些陷阱,我们可以使用上述解决方法。