函数参数解构是ES6中的一个了不起的功能。
假设我们希望function
名为f
的{{1}}接受Object
密钥
a
我们有一个默认值,当参数未提供给函数以避免function f({ a }) {
return a;
}
Type Error
这将有助于以下情况
function f({ a } = {}) {
return a;
}
但是,它会失败
const a = f(); // undefined
您可以看到Babel如何将该功能转换为ES5 here。
可以通过参数验证和预处理来避免。在const a = f(null); // TypeError: Cannot match against 'undefined' or 'null'.
我可以使用装饰器,但在JS中我们没有标准化,所以使用它们不是一个好主意。
但是,假设我们有一个装饰器Python
,它使用给定的项目列表(或嵌套解构的情况下的树)进行必要的检查并提供默认值。
我们可以在没有checkInputObject
表示法的情况下以下列方式使用它
@
const f = checkInputObject(['a'])(({ a }) => a);
符号
@
此外,我可以在函数本身中进行所有需要的操作,然后才使用解构,但在这种情况下,我失去了函数参数解构的所有优点(我根本不会使用它)
@checkInputObject(['a'])
function f({ a }) {
return a;
}
我甚至可以实现一些常见的功能,如function f(param) {
if (!param) {
return;
}
const { a } = param;
return a;
}
,以便在函数
checkInputObject
虽然使用附加代码对我来说并不优雅。我希望将现有实体分解为const fChecker = checkInputObject(['a']);
function f(param) {
const { a } = fChecker(param);
return a;
}
。
假设我们有
undefined
在function f({a: [, c]) {
return c;
}
的情况下获得undefined
会很高兴。
您是否知道任何优雅且方便的方法使[嵌套]解构能够抵抗不存在的嵌套键?
我关注的是:看起来这个功能对于在公共方法中使用是不安全的,我需要在使用它之前自己进行验证。这就是为什么在私人方法中使用它之前似乎无用的原因。
答案 0 :(得分:3)
您可以使用try...catch
并在通用装饰器函数中使用它:
function safe(f) {
return function (...args) {
try {
return f(...args);
} catch (e) {}; // return undefined
};
}
function f({ a } = {}) {
return a;
}
f = safe(f);
console.log(f(null)); // -> undefined
console.log(f( { a:3 } )); // -> 3

答案 1 :(得分:2)
我相信我可以通过向您展示不同的方式来帮助您解决此问题。
你所面临的问题不在于解构,因为你会在任何你发送它不同类型的函数中面对它。
解决此类问题,例如在解构时,您可以使用类型检查解决方案,例如Flow,它会静态检查类型,因此每当您向函数发送错误的内容时,它都会在构建时失败。
javascript的本质是它是一种动态类型语言,因此您可能希望该函数能够处理发送给它的任何参数,在这种情况下,您可以使用动态类型检查,解决方案很多。 / p>
函数参数更多地是对使用函数的“协议”,而不是访问它的参数(毕竟你可以使用arguments
来访问它们),因此通过发送你违反的不同的东西这个协议,这不是一个好的做法,最好有1个功能做1件事,并且接受尽可能少的复杂参数。
答案 2 :(得分:2)
在ES6中处理此问题的正确方法是尊重语言和形状API处理params的方式以更好地适应它,而不是相反的方式。
fn(undefined)
中的destructured参数背后的语义是,参数将被替换为默认值,在fn(null)
的情况下,意味着nully参数不会被默认值替换。 / p>
如果数据来自外部并且应该进行调节/预处理/验证,则应该明确处理,而不是通过解构:
function fn({ foo, bar}) { ... }
fn(processData(data));
或
function fn(data) {
const { foo, bar } = processData(data);
...
}
fn(data);
应该调用processData
的地方完全由开发人员自行决定。
由于提议的ECMAScript装饰器只是具有特定签名的辅助函数,因此可以使用相同的辅助函数@
语法和常规函数调用,具体取决于项目。
function processDataDecorator(target, key) {
const origFn = target[key];
return target[key] = (...args) => origFn.apply(target, processData(...args));
}
class Foo {
constructor() {
this.method = processDataDecorator(this, 'method');
}
method(data) {...}
}
class Bar {
@processDataDecorator
method(data) {...}
}
自ES5以来,语言为默认属性值提供的方式是Object.assign
。如果data
是undefined
,null
或其他原语,那么结果将始终是一个对象并不重要:
function processData(data) {
return Object.assign({ foo: ..., bar: ...}, data);
}
答案 3 :(得分:-3)
你不是只回答自己问的问题吗?
我认为默认参数是更优雅的方式。
gl_FragCoord