在 ES6 中将 NULL 作为参数传递时,在提供时不使用默认参数
Passing in NULL as a parameter in ES6 does not use the default parameter when one is provided
为什么在 ES6 中将 null
作为参数传递时不使用默认参数的已知原因是什么?
function sayHello(name = "World") {
console.log("Hello, " + name + "!");
}
sayHello("Jim"); // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null); // Hello, null!
null
是不会触发使用默认值的值,当参数为 undefined
.
时将使用默认值
规范中就是这样定义默认参数的。参见 MDN:(强调我的)
Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.
null
既不是无值,也不是undefined
,所以它不会触发默认初始化。
这不是那么明显
我读过一些关于为什么 undefined
与 null
完全不同的评论,这就是为什么它解释了默认参数的当前行为。
有人可能会争辩说显式传递未定义的 不应该 触发默认值替换,因为当我有一个函数时:
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]
这清楚地表明:
- 传递
undefined
与根本不传递参数不同
- 有时
null
可以是 默认值而不是 undefined
TC39 决定
关于默认参数当前行为的一些背景可以在 2012 年 7 月 24 日的 TC39 会议记录中看到:
顺便说一下,它表明显式传递 undefined
最初 并没有 触发初稿中的默认值,并且讨论了是否应该这样做那。因此,正如您所看到的,当前的行为对于 TC39 成员来说并不像现在对在这里发表评论的人来说那么明显。
其他语言
话虽如此,决定什么应该和什么不应该触发默认值替换最终完全是任意的。如果你仔细想想,即使有一个单独的 undefined
和 null
也会觉得很奇怪。有些语言只有 undefined
(如 Perl 中的 undef
),有些只有 null
(如 Java),有些语言使用等价的 false
或一个空的列表或数组(比如 Scheme,你可以有一个空列表或 #f
(false) 但没有 null
的等价物可以区别于空列表和假值)和有些语言甚至没有 null
、false
或 undefined
的等价物(比如 C 使用整数而不是 true
和 false
以及一个 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)));
如果你想替换空 objects,你可以使用:
const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));
等等...
结论
关键是这是您的代码,您知道函数的 API 应该是什么以及默认值应该如何工作。幸运的是 Java脚本足够强大,可以让您通过一些高阶函数魔术轻松实现您需要的功能(即使这不是默认值的默认行为,可以这么说)。
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
为什么在 ES6 中将 null
作为参数传递时不使用默认参数的已知原因是什么?
function sayHello(name = "World") {
console.log("Hello, " + name + "!");
}
sayHello("Jim"); // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null); // Hello, null!
null
是不会触发使用默认值的值,当参数为 undefined
.
规范中就是这样定义默认参数的。参见 MDN:(强调我的)
Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.
null
既不是无值,也不是undefined
,所以它不会触发默认初始化。
这不是那么明显
我读过一些关于为什么 undefined
与 null
完全不同的评论,这就是为什么它解释了默认参数的当前行为。
有人可能会争辩说显式传递未定义的 不应该 触发默认值替换,因为当我有一个函数时:
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]
这清楚地表明:
- 传递
undefined
与根本不传递参数不同 - 有时
null
可以是 默认值而不是undefined
TC39 决定
关于默认参数当前行为的一些背景可以在 2012 年 7 月 24 日的 TC39 会议记录中看到:
顺便说一下,它表明显式传递 undefined
最初 并没有 触发初稿中的默认值,并且讨论了是否应该这样做那。因此,正如您所看到的,当前的行为对于 TC39 成员来说并不像现在对在这里发表评论的人来说那么明显。
其他语言
话虽如此,决定什么应该和什么不应该触发默认值替换最终完全是任意的。如果你仔细想想,即使有一个单独的 undefined
和 null
也会觉得很奇怪。有些语言只有 undefined
(如 Perl 中的 undef
),有些只有 null
(如 Java),有些语言使用等价的 false
或一个空的列表或数组(比如 Scheme,你可以有一个空列表或 #f
(false) 但没有 null
的等价物可以区别于空列表和假值)和有些语言甚至没有 null
、false
或 undefined
的等价物(比如 C 使用整数而不是 true
和 false
以及一个 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)));
如果你想替换空 objects,你可以使用:
const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));
等等...
结论
关键是这是您的代码,您知道函数的 API 应该是什么以及默认值应该如何工作。幸运的是 Java脚本足够强大,可以让您通过一些高阶函数魔术轻松实现您需要的功能(即使这不是默认值的默认行为,可以这么说)。
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