ES6解构预处理

时间:2017-06-10 12:41:07

标签: javascript ecmascript-6 destructuring

问题

函数参数解构是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会很高兴。

问题

您是否知道任何优雅且方便的方法使[嵌套]解构能够抵抗不存在的嵌套键?

我关注的是:看起来这个功能对于在公共方法中使用是不安全的,我需要在使用它之前自己进行验证。这就是为什么在私人方法中使用它之前似乎无用的原因。

4 个答案:

答案 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。如果dataundefinednull或其他原语,那么结果将始终是一个对象并不重要:

function processData(data) {
  return Object.assign({ foo: ..., bar: ...}, data);
}

答案 3 :(得分:-3)

你不是只回答自己问的问题吗?

我认为默认参数是更优雅的方式。

gl_FragCoord