【问题标题】:Passing in NULL as a parameter in ES6 does not use the default parameter when one is provided在 ES6 中将 NULL 作为参数传入,在提供时不使用默认参数
【发布时间】:2015-12-19 21:54:41
【问题描述】:

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

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

sayHello("Jim");     // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null);      // Hello, null!

【问题讨论】:

  • 因为 null 是有效值?
  • @toskv undefined..
  • 不,不是 :) 你可以在这里阅读 undefined 和 null 之间的区别stackoverflow.com/questions/5076944/…
  • @toskv 如果undefined 不是一个值,那么它可以被赋值,但它可以被赋值。这是确定某物是否为值的最简单测试。很简单,这个答案在上下文中使用是错误的:undefined 在某些情况下被用作 默认值;这不是使未定义的“不是一个值”。考虑:a = new Array(1)。然后a[0] 将产生undefined 值,即使0 in a 为假。也就是说,a[0] 包含“无价值”,即使它会评估为(默认)undefined 值。
  • @toskv 我已经在上面解释了为什么这是不正确的。谈论“如果未定义变量”(在 typeof x === 'undefined' 的情况下,单独的 x 会/可能抛出 ReferenceError)与 undefined is 的事实无关价值。特别是,JavaScript 中的“未定义”not 严格表示“尚未定义/声明”。

标签: javascript ecmascript-6 optional-parameters


【解决方案1】:

这不是很明显

我已经阅读了一些关于为什么 undefinednull 完全不同的问题,这就是为什么它解释了默认参数的当前行为。

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

const f = (x = 'default') => console.log(x);

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

f();

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

f(undefined);

因为否则我为什么要首先使用f(undefined)?显然,我的意图是提供一些论据而不是忽略它。

相反的例子

现在,考虑这个函数:

const g = (...a) => console.log(JSON.stringify(a));

当我把它用作:

g();

我得到:[]

但是当我把它用作:

g(undefined);

我得到:[null]

这清楚地表明:

  1. 传递undefined 与根本不传递参数不一样
  2. 有时null 可以是默认值而不是undefined

TC39 决定

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

顺便说一句,它表明最初显式传递undefined并没有触发初稿中的默认值,并且讨论了是否应该这样做。因此,您可以看到当前的行为对 TC39 成员来说并不像现在对在这里发表评论的人那样明显。

其他语言

话虽如此,最终决定什么应该和什么不应该触发默认值替换是完全任意的。如果您考虑一下,即使有一个单独的undefinednull 也可能会很奇怪。有些语言只有undefined(如Perl 中的undef),有些只有null(如Java),有些语言使用false 的等价物或空列表或数组(如您可以拥有的Scheme空列表或 #f (false),但没有与空列表和 false 值不同的 null 等价物)并且某些语言甚至没有 nullfalse 的等价物或undefined (如使用整数而不是truefalse 的C 和一个NULL 指针,它实际上是一个指向地址0 的普通指针——即使由任何测试空指针的代码映射,该地址也无法访问) .

你能做什么

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

const N = f => (...a) => f(...a.map(v => (v === null ? undefined : v)));

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

const f = (x = 'default') => console.log(x);

它将为f()f(undefined) 打印"default",但不会为f(null) 打印。但是当你使用上面定义的N函数来定义f函数时:

const f = N((x = 'default') => console.log(x));

现在f()f(undefined) 以及f(null) 打印"default"

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

const N = f => (...a) => f(...a.map(v => (v === '' ? undefined : v)));

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

const N = f => (...a) => f(...a.map(v => (v || undefined)));

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

const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));

等等……

结论

关键是它是您的代码,您知道函数的 API 应该是什么以及默认值应该如何工作。幸运的是,JavaScript 足够强大,可以让您通过一些高阶函数魔法轻松实现所需(即使这不是默认值的默认行为)。

【讨论】:

  • 很棒的答案!非常深入且解释清楚。
  • 现在,显式传递 undefined 应该触发默认值替换
  • @rsp,感谢您的回答,四年后我准确地找到了问题的原因。
【解决方案2】:

ramdajs 版本代码

// import ramda

// infra code
const isEmptyOrNil = (value) => isEmpty(value) || isNil(value)
const nullChange = (defaultValue) => (value) => isEmptyOrNil(value)? defaultValue: value

// single null
const _somef = (value) => value
const somefWithDefault = (defaultValue) => pipe(nullChange(defaultValue), _somef)
const somef = somefWithDefault('myValue')

somef(null)

// many args
const _somef2 = (value, value2, value3) => value + value2 + value3
const nullChangeMyValue = nullChange('myValue')
const somef2 = useWith(_somef2, [nullChangeMyValue, nullChangeMyValue, nullChangeMyValue])

somef2(null, undefined, 1234)

// many args2 version2
const nullChangeWith = (defaultValue) => nullChange(defaultValue)
const arrayNullChangeWith = (defaultValue) => (array) => array.map(nullChangeWith(defaultValue))
const arg2Array = (...args) => args
const funcApplyDefaultValue = (defaultValue) => (func) => pipe(
  arg2Array, arrayNullChangeWith(defaultValue), apply(func)
)

const v2somef2 = funcApplyDefaultValue(8)(_somef2)

v2somef2(1,2,null)

gits:https://gist.github.com/otwm/3a6358e53ca794cc2e57ade4af91d3bb

【讨论】:

    【解决方案3】:

    null是一个不会触发使用默认值的值,当参数为undefined时会使用默认值。

    【讨论】:

      【解决方案4】:

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

      默认函数参数允许在传递无值或未定义时使用默认值初始化形式参数。

      null既不是无值,也不是undefined,所以不会触发默认初始化。

      【讨论】:

      • 而之所以对undefined进行特殊处理,是因为“空”参数设置为undefined。如果undefined 不等于“无价值”,那么实现起来会更烦人:function foo(bar) { return functionWithDefaults(bar); }; foo();。缺点是无法显式传递undefined,但无论如何谁会这样做:P
      • 有谁知道他们为什么认为这是正确的方法?在我看来 null 应该触发使用默认值。
      • 可以通过显式传递undefined 显式传递undefined,例如doSomething(undefined),见codepen.io/morewry/pen/KaEVmN?editors=0010
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      • 1970-01-01
      • 2011-02-23
      相关资源
      最近更新 更多