在ES6中作为参数传递NULL时,在提供一个参数时不使用默认参数

aus*_*acy 46 javascript optional-parameters ecmascript-6

是否有一个已知的原因,为什么在null提供一个参数时,作为ES6中的参数传入时不使用默认参数?

function sayHello(name = "World") {
    console.log("Hello, " + name + "!");
}

sayHello("Jim");     // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null);      // Hello, null!
Run Code Online (Sandbox Code Playgroud)

dol*_*ldt 29

这就是规范中定义默认参数的方式.见MDN :(强调我的)

如果没有传递值或未定义,则默认函数参数允许使用默认值初始化形式参数.

null既不是也不是undefined,因此它不会触发默认初始化.

  • 有谁知道为什么他们认为这是正确的方法?在我看来null应该触发使用默认值. (4认同)

rsp*_*rsp 25

这不是那么明显

我已经阅读了一些关于为何undefined与完全不同的评论,这就是null为什么它解释了默认参数的当前行为.

有人可能会争辩说显式传递undefined不应该触发默认值替换,因为当我有一个函数时:

const f = (x = 'default') => console.log(x);
Run Code Online (Sandbox Code Playgroud)

我希望它"default"在我运行时打印:

f();
Run Code Online (Sandbox Code Playgroud)

但我希望它"undefined"在我明确地运行时打印:

f(undefined);
Run Code Online (Sandbox Code Playgroud)

因为否则我为什么要f(undefined)首先使用?显然,我的意图是提供一些论据,而不是将其遗漏.

相反的例子

现在,考虑这个功能:

const g = (...a) => console.log(JSON.stringify(a));
Run Code Online (Sandbox Code Playgroud)

当我用它时:

g();
Run Code Online (Sandbox Code Playgroud)

我明白了: []

但当我用它时:

g(undefined);
Run Code Online (Sandbox Code Playgroud)

我明白了: [null]

这清楚地表明:

  1. 传球undefined不一样的不传递一个参数都
  2. 有时null 可以是默认值而不是undefined

TC39的决定

有关默认参数当前行为的一些背景信息可以在TC39的2012年7月24日会议记录中看到:

顺便提一下,它表明显式传递undefined最初没有触发第一个草稿中的默认值,并且讨论了它是否应该这样做.因此,您可以看到TC39成员目前的行为并不那么明显,因为现在似乎是在这里发表评论的人.

其他语言

话虽如此,在一天结束时,应该和不应该触发默认值替换的决定是完全任意的.即使有一个单独的undefined,null如果你考虑它可以是非常奇怪的.有些语言只有undefined(比如undef在Perl中),有些null语言只有(比如Java),有些语言使用等价物false或者是空列表或数组(就像Scheme中你可以有一个空列表或#f(false)但是没有相应的语言的null,这将是从两个空列表和一个假值不同)和某些语言甚至没有的当量null,falseundefined(如一个使用整数代替C truefalse和一个NULL指针这实际上是一个正常的指针指向地址0 - 即使在测试空指针的任何代码映射时,也使该地址不可访问.

你可以做什么

现在,我可以理解您需要替换默认值null.不幸的是,这不是默认行为,但您可以创建一个简单的函数来帮助您:

const N = f => (...a) => f(...a.map(v => (v === null ? undefined : v)));
Run Code Online (Sandbox Code Playgroud)

现在,每当您希望默认值替换null值时,您可以像这样使用它.例如,如果您从上面的一个示例中获得此功能:

const f = (x = 'default') => console.log(x);
Run Code Online (Sandbox Code Playgroud)

它会打印"default"f()f(undefined),但不适合f(null).但是当你使用N上面定义的f函数来定义这样的函数时:

const f = N((x = 'default') => console.log(x));
Run Code Online (Sandbox Code Playgroud)

现在f(),f(undefined)但也f(null)打印"default".

如果您想要稍微不同的行为,例如将默认值替换为空字符串 - 对于有时可以设置为空字符串而不是不存在的环境变量很有用,您可以使用:

const N = f => (...a) => f(...a.map(v => (v === '' ? undefined : v)));
Run Code Online (Sandbox Code Playgroud)

如果你想要替换所有的假值,你可以像这样使用它:

const N = f => (...a) => f(...a.map(v => (v || undefined)));
Run Code Online (Sandbox Code Playgroud)

如果您想要替换空对象,您可以使用:

const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));
Run Code Online (Sandbox Code Playgroud)

等等...

结论

关键是它是你的代码,你知道你的函数的API应该是什么以及默认值应该如何工作.幸运的是,JavaScript足够强大,可以让你轻松地实现你需要的东西(即使这不是默认值的默认行为,可以这么说),具有一些更高阶函数的魔力.

  • 真棒的答案!非常深入和充分解释. (2认同)