逗號運算子是類別C語言(例如JavaScript和C++)中較不為人所知的運算子之一。本質上,它界定了一系列表達式並僅傳回最後一個表達式的結果。
const a = 1; const b = 2; const c = 3; const result = (a, b, c, 4, 5, 6, true); console.log(result); // true
if (false, true) console.log('hello'); // hello
很自然地會問:什麼時候將多個表達式塞進一行會有用? 此外,即使它有用,為什麼用逗號分隔的表達式序列(在單行)比分號分隔的語句序列(跨多行)更具可讀性和可維護性?我們什麼時候應該選擇其中一種而不是另一種?
這些是我多年來一直努力回答的問題,但現在我想我終於有了答案。在本文中,我針對逗號運算子提出了一個令人信服的案例(坦白說,也許是唯一的案例)。
我們先來說一下條件三元運算子。如下圖所示,如果條件為真,則評估值。否則,它評估另一個。這裡強調關鍵字“評估”,因為分支僅在滿足條件時執行。
const result = condition ? value : another;
在大多數情況下,它都是整潔漂亮的。然而,當我們需要在返回條件值之前在分支之間執行更複雜的邏輯時,它就會崩潰。此時,我們訴諸這種不幸的變態:
let result; // Uninitialized! Yikes! if (condition) { // Do some complex stuff in between... doSomething(); // ... result = value; // Actual Assignment } else { // Do other complex stuff in between... doAnotherThing(); // ... result = another; // Actual Assignment } // Hopefully we didn't forget to initialize `result`!
現在這個配方存在很多問題。
如果我們堅持使用條件三元表達式,就有辦法繞過這個限制。我們只需要將程式碼重構為函數即可。這絕對是說來容易做來難。這個噱頭很快就過時了!
function computeWrappedValue() { // ... return value; } function computeWrappedAnother() { // ... return another; } // How cumbersome! const result = condition ? computeWrappedValue() : computeWrappedAnother();
基於表達式的程式語言(例如 Rust)有更優雅的解決方案。透過將 if 語句 重新分類為 if 表達式 ,可以對每個分支進行求值,從而傳回稍後可以儲存在變數中的值。
// A conditional ternary operator thus looks like this. Each branch // returns a value, which is captured by the `result` variable. // We thus ensure that `result` is always initialized by construction. let result = if condition { value } else { another };
// If we wanted to do something more complex, we use the same syntax. let result = if condition { do_something(); // In Rust, the last expression without a semicolon is the value // that will be "returned" by the overall `if` expression. result } else { do_another_thing(); another };
我們可以用類似 C 的語言來模擬這個嗎? 你可能早就預見了我的發展方向,但是可以!
我們想要的是一種在傳回三元分支內的值之前任意執行語句的方法。好吧,對我們來說幸運的是,這正是逗號運算符的用途。
// Parenthesized for clarity. const result = condition ? (doSomething(), value) // evaluates to `value` : (doAnotherThing(), another); // evaluates to `another`
這個公式的巧妙之處在於,分支表達式在必要時才進行計算。我們有效地模擬基於表達式的程式語言的行為。臨時包裝函數的時代已經一去不復返了!
但可惜,我們只能用這種技術走這麼遠。你可以想像,對於一些夠大的 n,將 n 條語句塞進一行已經需要重構到它自己的函數中。就我個人而言,到 n > 時我已經重新考慮了。 3. 就可讀性而言,任何高於此值的結構都是可疑的。
// Maybe we should reconsider here? const result = condition ? (x++, thing = hello(), doSomething(), value) : (++y, thing = world(), doAnotherThing(), another);
// Okay, stop. Definitely turn back now! const result = condition ? ( x++, thing = hello(), doSomething(), doMore(y), doEvenMore(thing), value, ) : ( ++y, thing = world(), doAnotherThing(), doMore(y), doEvenMore(thing), another, ); // Unless, of course, you're fine with this. It kinda does // look like a Rust `if` expression if you squint hard enough.
總而言之,我們看到了逗號運算子的一個令人信服的案例:複雜的條件三元運算。當分支又短又甜時,逗號運算子會大放異彩,但在三個內聯語句之後很快就會過時。到那時,重構程式碼可能會更好。
那你應該使用逗號運算子嗎? 老實說......是的!可讀的程式碼會考慮到下一個讀者,因此只要逗號鏈不會太長,我就會接受甚至鼓勵這種編碼風格。如果我們考慮替代方案(即未初始化的變數和重構的微函數),逗號運算子畢竟沒那麼糟。
在實務中,我已經在自己的程式碼庫中加入了這些看起來很有趣的逗號運算子。但公平地說,我很少需要多語句三元條件。但當我這樣做時,我的腰帶上就有了一個很酷的工具,可以簡潔地表達我的意圖。
為此,我對逗號運算符提出了令人信服的理由。
以上是逗號運算子的一個令人信服的案例的詳細內容。更多資訊請關注PHP中文網其他相關文章!