ES6 解构预处理
ES6 destructuring preprocessing
问题
函数参数解构是 ES6 中的一个了不起的特性。
假设我们想要一个名为 f
的 function
接受一个 Object
,它有一个 a
key
function f({ a }) {
return a;
}
当参数未提供给函数时,我们有默认值以避免 Type Error
function f({ a } = {}) {
return a;
}
这将有助于以下情况
const a = f(); // undefined
不过,它会在
上失败
const a = f(null); // TypeError: Cannot match against 'undefined' or 'null'.
您可以看到 Babel 如何将函数转译为 ES5 here。
可能的解决方案
可以通过参数验证和预处理来避免。在 Python
中我可以使用装饰器,但在 JS 中我们没有将它们标准化,所以现在使用它们不是一个好主意。
但是,假设我们有一个装饰器 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;
}
在f()
的情况下得到undefined
就好了。
问题
您是否知道任何使 [嵌套] 解构对不存在的嵌套键具有抵抗力的优雅便捷的方法?
我的担忧如下:似乎这个功能在 public 方法中使用是不安全的,我需要在使用它之前自己进行验证。这就是为什么在私有方法中使用之前它似乎毫无用处。
你不是自己回答了你问的问题吗?
我认为默认参数是更优雅的方式。
function f({a: [,c]}={a:[undefined,undefined]}) {
return c;
}
f();
我相信我可以通过向您展示不同的方式来帮助您解决这个问题。
您面临的问题与解构无关,因为您将在发送给它的任何函数中遇到它所期望的不同类型。
解决此类问题,例如。解构,您可以使用类型检查解决方案,例如 Flow,它静态检查类型,因此只要您向函数发送错误的内容,它就会在构建时失败。
javascript 的本质是它是一种动态类型语言,因此您可能希望该函数能够处理发送给它的任何参数,在这种情况下,您可以使用动态类型检查,解决方案很多。
函数参数更多的是 "agreement" 你如何使用函数,而不是访问它的参数(毕竟你可以只使用 arguments
来访问它们),因此通过发送不同的你违反了这个协议,无论如何这不是一个好的做法,最好有 1 个函数做 1 件事,并接受尽可能少的复杂参数。
您可以使用 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
在 ES6 中处理这个问题的正确方法是尊重语言处理参数的方式和形状 API 以更好地适应它,而不是以相反的方式。
fn(undefined)
中解构参数背后的语义是参数将被替换为默认值,在fn(null)
的情况下意味着空参数不会被替换为默认值。
如果数据来自外部并且应该是conditioned/preprocessed/validated,这应该被显式处理,而不是通过解构:
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);
}
问题
函数参数解构是 ES6 中的一个了不起的特性。
假设我们想要一个名为 f
的 function
接受一个 Object
,它有一个 a
key
function f({ a }) {
return a;
}
当参数未提供给函数时,我们有默认值以避免 Type Error
function f({ a } = {}) {
return a;
}
这将有助于以下情况
const a = f(); // undefined
不过,它会在
上失败const a = f(null); // TypeError: Cannot match against 'undefined' or 'null'.
您可以看到 Babel 如何将函数转译为 ES5 here。
可能的解决方案
可以通过参数验证和预处理来避免。在 Python
中我可以使用装饰器,但在 JS 中我们没有将它们标准化,所以现在使用它们不是一个好主意。
但是,假设我们有一个装饰器 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;
}
在f()
的情况下得到undefined
就好了。
问题
您是否知道任何使 [嵌套] 解构对不存在的嵌套键具有抵抗力的优雅便捷的方法?
我的担忧如下:似乎这个功能在 public 方法中使用是不安全的,我需要在使用它之前自己进行验证。这就是为什么在私有方法中使用之前它似乎毫无用处。
你不是自己回答了你问的问题吗?
我认为默认参数是更优雅的方式。
function f({a: [,c]}={a:[undefined,undefined]}) {
return c;
}
f();
我相信我可以通过向您展示不同的方式来帮助您解决这个问题。
您面临的问题与解构无关,因为您将在发送给它的任何函数中遇到它所期望的不同类型。
解决此类问题,例如。解构,您可以使用类型检查解决方案,例如 Flow,它静态检查类型,因此只要您向函数发送错误的内容,它就会在构建时失败。
javascript 的本质是它是一种动态类型语言,因此您可能希望该函数能够处理发送给它的任何参数,在这种情况下,您可以使用动态类型检查,解决方案很多。
函数参数更多的是 "agreement" 你如何使用函数,而不是访问它的参数(毕竟你可以只使用 arguments
来访问它们),因此通过发送不同的你违反了这个协议,无论如何这不是一个好的做法,最好有 1 个函数做 1 件事,并接受尽可能少的复杂参数。
您可以使用 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
在 ES6 中处理这个问题的正确方法是尊重语言处理参数的方式和形状 API 以更好地适应它,而不是以相反的方式。
fn(undefined)
中解构参数背后的语义是参数将被替换为默认值,在fn(null)
的情况下意味着空参数不会被替换为默认值。
如果数据来自外部并且应该是conditioned/preprocessed/validated,这应该被显式处理,而不是通过解构:
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);
}