論理代入

公開日: · タグ: ECMAScript ES2021

JavaScript は、プログラマーが二項演算と代入を簡潔に表現できる、さまざまな複合代入演算子をサポートしています。現在、サポートされているのは算術演算またはビット演算のみです。

欠けていたのは、論理演算と代入を組み合わせる機能です。それがついに実現しました! JavaScript は、新しい演算子 &&=||=、および ??= による論理代入をサポートするようになりました。

論理代入演算子 #

新しい演算子について詳しく掘り下げる前に、既存の複合代入演算子についておさらいしましょう。たとえば、lhs += rhs の意味は、おおよそ lhs = lhs + rhs と同等です。このおおよその同値性は、既存のすべての演算子 @= (@ は、+| のような二項演算子を表す) に当てはまります。厳密に言えば、これが正しいのは lhs が変数の場合のみであることに注意してください。obj[computedPropertyName()] += rhs のようなより複雑な左辺の場合、左辺は一度だけ評価されます。

それでは、新しい演算子について詳しく見ていきましょう。既存の演算子とは対照的に、@ が論理演算 (&&||、または ??) である場合、lhs @= rhs はおおよそ lhs = lhs @ rhs を意味しません。

// As an additional review, here is the semantics of logical and:
x && y
// → y when x is truthy
// → x when x is not truthy

// First, logical and assignment. The two lines following this
// comment block are equivalent.
// Note that like existing compound assignment operators, more complex
// left-hand sides are only evaluated once.
x &&= y;
x && (x = y);

// The semantics of logical or:
x || y
// → x when x is truthy
// → y when x is not truthy

// Similarly, logical or assignment:
x ||= y;
x || (x = y);

// The semantics of nullish coalescing operator:
x ?? y
// → y when x is nullish (null or undefined)
// → x when x is not nullish

// Finally, nullish coalescing assignment:
x ??= y;
x ?? (x = y);

ショートサーキットセマンティクス #

算術演算子やビット演算子とは異なり、論理代入は、それぞれの論理演算のショートサーキット動作に従います。つまり、論理演算が右辺を評価する場合にのみ代入を実行します。

最初は混乱するかもしれません。他の複合代入のように、左辺に無条件に代入しないのはなぜでしょうか?

この違いには、実用的な理由があります。論理演算と代入を組み合わせる場合、代入によって副作用が発生する可能性があり、その副作用は論理演算の結果に基づいて条件付きで発生する必要があります。副作用を無条件に発生させると、プログラムのパフォーマンスや正確性に悪影響を及ぼす可能性があります。

要素にデフォルトのメッセージを設定する 2 つのバージョンの関数を例に、これを具体的に見てみましょう。

// Display a default message if it doesn’t override anything.
// Only assigns to innerHTML if it’s empty. Doesn’t cause inner
// elements of msgElement to lose focus.
function setDefaultMessage() {
msgElement.innerHTML ||= '<p>No messages<p>';
}

// Display a default message if it doesn’t override anything.
// Buggy! May cause inner elements of msgElement to
// lose focus every time it’s called.
function setDefaultMessageBuggy() {
msgElement.innerHTML = msgElement.innerHTML || '<p>No messages<p>';
}

注: innerHTML プロパティは、null または undefined の代わりに空の文字列を返すように指定されているため、??= の代わりに ||= を使用する必要があります。コードを記述するときは、多くの Web API が、空または欠落を意味するために null または undefined を使用していないことに注意してください。

HTML では、要素の .innerHTML プロパティへの代入は破壊的です。内部の子要素は削除され、新しく代入された文字列から解析された新しい子要素が挿入されます。新しい文字列が古い文字列と同じ場合でも、追加の作業が発生し、内部要素がフォーカスを失います。このような不要な副作用を起こさないという実用的な理由から、論理代入演算子のセマンティクスは代入をショートサーキットします。

次の方法で他の複合代入演算子との対称性について考えると役立つかもしれません。算術演算子とビット演算子は無条件であるため、代入も無条件です。論理演算子は条件付きであるため、代入も条件付きです。

論理代入のサポート #