[英]ES6 destructuring preprocessing
函數參數解構是ES6中的一個驚人特性。 假設我們希望有一個function
叫f
接受的Object
,其具有a
鍵
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。
通過參數驗證和預處理可以避免這種情況。 在Python
我可以使用裝飾器,但在JS中我們沒有標准化,所以使用它們並不是一個好主意。 但是,假設我們有一個裝飾器checkInputObject
,它使用給定的項目列表(或嵌套解構的情況下的樹)進行必要的檢查並提供默認值。 我們可以在沒有@
notation的情況下以下列方式使用它
const f = checkInputObject(['a'])(({ a }) => a);
@
notation可能看起來像這樣
@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
會很好。
你知道任何優雅和方便的方法使[嵌套]解構抵抗不存在的嵌套鍵嗎?
我關注的是:看起來這個功能對於在公共方法中使用是不安全的,我需要在使用之前自己進行驗證。 這就是為什么它在私人方法中使用之前似乎毫無用處。
您可以使用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
我相信我可以通過向您展示不同的方式來幫助您解決此問題。
您面臨的問題不在於解構,因為您將在任何函數中面對它,而您正在發送它所期望的不同類型。
解決這個問題,例如 在解構時,您可以使用類型檢查解決方案,例如Flow ,它會靜態檢查類型,因此每當您向函數發送錯誤的內容時,它都會在構建時失敗。
javascript的本質是它是一種動態類型語言,因此您可能希望該函數能夠處理發送給它的任何參數,在這種情況下,您可以使用動態類型檢查,解決方案很多。
函數參數更多地是你對如何使用函數的“協議”,而不是訪問它的參數(畢竟你可以只使用arguments
來訪問它們),因此通過發送不同的東西你違反了這個協議,這不是不管怎樣,一個好的做法,最好有1個功能做1件事,並盡可能少地接受復雜的參數。
在ES6中處理這個問題的正確方法是尊重語言和形狀API處理params的方式以更好地適應它,而不是相反的方式。
fn(undefined)
析構參數背后的語義是參數將被替換為默認值,在fn(null)
的情況下,nully參數不會被默認值替換。
如果數據來自外部並且應該進行條件/預處理/驗證,則應該明確處理,而不是通過解構:
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);
}
難道你不是自己回答你問的問題嗎?
我認為默認參數是更優雅的方式。
function f({a: [,c]}={a:[undefined,undefined]}) {
return c;
}
f();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.