JavaScript for impatient programmers (ES2022 版)
この本をサポートしてください: 購入する または 寄付する
(広告です。ブロックしないでください。)

13 演算子



13.1 演算子の意味を理解する

JavaScript の演算子は奇妙に見えるかもしれません。次の 2 つのルールを理解すれば、より簡単に理解できます。

13.1.1 演算子はオペランドを適切な型に強制変換する

演算子が適切な型ではないオペランドを受け取った場合、例外をスローすることはまれです。代わりに、演算を実行できるように、オペランドを*強制変換*(自動的に変換)します。 2 つの例を見てみましょう。

まず、乗算演算子は数値でのみ動作します。したがって、結果を計算する前に文字列を数値に変換します。

> '7' * '3'
21

次に、オブジェクトのプロパティにアクセスするための角括弧演算子 ([ ]) は、文字列とシンボルのみを処理できます。他のすべての値は文字列に強制変換されます。

const obj = {};
obj['true'] = 123;

// Coerce true to the string 'true'
assert.equal(obj[true], 123);

13.1.2 ほとんどの演算子はプリミティブ値でのみ動作する

前述のように、ほとんどの演算子はプリミティブ値でのみ動作します。オペランドがオブジェクトの場合、通常はプリミティブ値に強制変換されます。例:

> [1,2,3] + [4,5,6]
'1,2,34,5,6'

なぜでしょうか?プラス演算子は、まずオペランドをプリミティブ値に強制変換します。

> String([1,2,3])
'1,2,3'
> String([4,5,6])
'4,5,6'

次に、2 つの文字列を連結します。

> '1,2,3' + '4,5,6'
'1,2,34,5,6'

13.2 プラス演算子 (+)

JavaScript のプラス演算子は次のように動作します。

文字列モードでは、+ を使用して文字列を組み立てることができます。

> 'There are ' + 3 + ' items'
'There are 3 items'

数値モードでは、オペランドのいずれも文字列(または文字列になるオブジェクト)でない場合、すべてが数値に強制変換されることを意味します。

> 4 + true
5

Number(true)1 です。

13.3 代入演算子

13.3.1 単純代入演算子

単純代入演算子は、ストレージの場所を変更するために使用されます。

x = value; // assign to a previously declared variable
obj.propKey = value; // assign to a property
arr[index] = value; // assign to an Array element

変数宣言のイニシャライザも代入の一種と見なすことができます。

const x = value;
let y = value;

13.3.2 複合代入演算子

JavaScript は次の代入演算子をサポートしています。

13.3.2.1 論理代入演算子 [ES2021]

論理代入演算子は、他の複合代入演算子とは異なる動作をします。

代入演算子 同等のもの a がの場合のみ代入
a ||= b a || (a = b) Falsy (偽)
a &&= b a && (a = b) Truthy (真)
a ??= b a ?? (a = b) Nullish (nullish)

a ||= b が次の式と同等なのはなぜですか?

a || (a = b)

なぜ次の式ではないのですか?

a = a || b

前の式には短絡評価の利点があります。代入は、afalse と評価された場合にのみ評価されます。したがって、代入は必要な場合にのみ実行されます。対照的に、後者の式は常に代入を実行します。

??= の詳細については、§14.4.5 「nullish 合体代入演算子 (??=) [ES2021]」を参照してください。

13.3.2.2 残りの複合代入演算子

|| && ?? 以外の演算子 op の場合、次の 2 つの代入方法は同等です。

myvar op= value
myvar = myvar op value

たとえば、op+ の場合、次のように動作する演算子 += が得られます。

let str = '';
str += '<b>';
str += 'Hello!';
str += '</b>';

assert.equal(str, '<b>Hello!</b>');

13.4 等価性: =====

JavaScript には、緩い等価性 (==) と厳密な等価性 (===) の 2 種類の等価演算子があります。常に後者を使用することをお勧めします。

  ===== の他の名前

13.4.1 緩い等価性 (==!=)

緩い等価性は、JavaScript の癖の 1 つです。多くの場合、オペランドを強制変換します。これらの強制変換の一部は意味をなします。

> '123' == 123
true
> false == 0
true

そうでないものもあります。

> '' == 0
true

オブジェクトは、他のオペランドがプリミティブの場合(そしてその場合にのみ!)、プリミティブに強制変換されます。

> [1, 2, 3] == '1,2,3'
true
> ['1', '2', '3'] == '1,2,3'
true

両方のオペランドがオブジェクトの場合、それらが同じオブジェクトである場合にのみ等しくなります。

> [1, 2, 3] == ['1', '2', '3']
false
> [1, 2, 3] == [1, 2, 3]
false

> const arr = [1, 2, 3];
> arr == arr
true

最後に、==undefinednull が等しいと見なします。

> undefined == null
true

13.4.2 厳密な等価性 (===!==)

厳密な等価性は決して強制変換しません。2 つの値は、型が同じである場合にのみ等しくなります。以前の == 演算子とのやり取りを再検討し、=== 演算子が何をするかを見てみましょう。

> false === 0
false
> '123' === 123
false

オブジェクトは、その値が同じオブジェクトである場合にのみ、他の値と等しくなります。

> [1, 2, 3] === '1,2,3'
false
> ['1', '2', '3'] === '1,2,3'
false

> [1, 2, 3] === ['1', '2', '3']
false
> [1, 2, 3] === [1, 2, 3]
false

> const arr = [1, 2, 3];
> arr === arr
true

=== 演算子は、undefinednull が等しいとは見なしません。

> undefined === null
false

13.4.3 推奨事項: 常に厳密な等価性を使用する

常に === を使用することをお勧めします。これにより、コードが理解しやすくなり、== の癖について考える必要がなくなります。

== の 2 つのユースケースと、代わりに推奨することを見てみましょう。

13.4.3.1 == のユースケース: 数値または文字列との比較

== を使用すると、値 x が数値であるか、文字列としての数値であるかを 1 回の比較で確認できます。

if (x == 123) {
  // x is either 123 or '123'
}

次の 2 つの代替案のいずれかを推奨します。

if (x === 123 || x === '123') ···
if (Number(x) === 123) ···

最初に遭遇したときに、x を数値に変換することもできます。

13.4.3.2 == のユースケース: undefined または null との比較

== のもう 1 つのユースケースは、値 xundefined または null のいずれであるかを確認することです。

if (x == null) {
  // x is either null or undefined
}

このコードの問題は、誰かがそのように書きたかったのか、それともタイプミスで === null を意味したのかがわからないことです。

次の 2 つの代替案のいずれかを推奨します。

if (x === undefined || x === null) ···
if (!x) ···

2 番目の代替案の欠点は、undefinednull 以外の値を受け入れることですが、これは JavaScript で確立されたパターンです(§15.3 「真偽値に基づく存在チェック」で詳細に説明します)。

次の 3 つの条件もほぼ同等です。

if (x != null) ···
if (x !== undefined && x !== null) ···
if (x) ···

13.4.4 === よりもさらに厳密: Object.is()

メソッド Object.is() は 2 つの値を比較します。

> Object.is(123, 123)
true
> Object.is(123, '123')
false

=== よりもさらに厳密です。たとえば、NaN (数値を含む計算のエラー値) は、それ自身と等しいと見なします。

> Object.is(NaN, NaN)
true
> NaN === NaN
false

それは時々役に立ちます。たとえば、それを使用して、Array メソッド .indexOf() の改良版を実装できます。

const myIndexOf = (arr, elem) => {
  return arr.findIndex(x => Object.is(x, elem));
};

myIndexOf() は配列内で NaN を見つけますが、.indexOf() は見つけません。

> myIndexOf([0,NaN,2], NaN)
1
> [0,NaN,2].indexOf(NaN)
-1

結果 -1 は、.indexOf() が配列内で引数を見つけることができなかったことを意味します。

13.5 順序演算子

表 3: JavaScript の順序演算子。
演算子 名前
< より小さい
<= 以下
> より大きい
>= 以上

JavaScript の順序演算子 (表3) は、数値と文字列の両方で動作します。

> 5 >= 2
true
> 'bar' < 'foo'
true

<=>= は、厳密な等価性に基づいています。

  順序演算子は人間の言語ではうまく機能しません

順序演算子は、大文字と小文字の区別やアクセント記号が含まれる場合など、人間の言語でテキストを比較するのには適していません。詳細については、§20.6 「文字列の比較」で説明します。

13.6 その他の様々な演算子

次の演算子については、本書の別の場所で説明します。

次の 2 つのサブセクションでは、めったに使用されない 2 つの演算子について説明します。

13.6.1 カンマ演算子

カンマ演算子は 2 つのオペランドを持ち、両方を評価して 2 番目のオペランドを返します。

> 'a', 'b'
'b'

この演算子の詳細については、Speaking JavaScript を参照してください。

13.6.2 void 演算子

void 演算子は、オペランドを評価して undefined を返します。

> void (3 + 2)
undefined

この演算子の詳細については、Speaking JavaScript を参照してください。

  クイズ

クイズアプリを参照してください。