コンテンツにスキップ

JavaScript/演算子

出典: フリー教科書『ウィキブックス(Wikibooks)』

演算子(えんざんし、operator)とは、2 + 3+のように、演算を表す記号のことです。2や3は被演算子(ひえんざんし、operandオペランド)といいます。JavaScriptには算術演算子以外にもさまざまな演算子があります。変数の代入で使用した=も演算子の一種ですし、コンマ,も演算子の一種です。 演算子はメソッドでは有りません。 演算子はメソッドと異なりオーバーロード出来ません。

算術演算子

[編集]

加算 (+)、減算 (-)、乗算 (*)、除算 (/) の四則演算をはじめとする基本的な算術演算子が存在します。数値は常に浮動小数点数として扱われます。 BigIntにも演算子を適用できますが、算術演算子の場合両方のオペランドがBigIntである必要があり異なる型が渡されると、暗黙の型変換は行われず TypeErroe となります。 数値の演算で NaN を返すケースは、BigIntではErrorとなります(例えばゼロ除算は数値ではNaNを返しますが、BigInt同士ではRangeErrorがthrowされます)。

JavaScriptの算術演算子
演算子 意味
a + b 加算
a - b 減算
a * b 乗算
a / b 除算
a % b 剰余
a ** b べき乗
+a 単項プラス(数値化)
-a 単項マイナス(算術否定)
a++ または ++a インクリメント
a-- または --a デクリメント

加算演算子 (+)

[編集]

加算演算子(かさんえんざんし、addition operator)は+です[1]

変数twoを1+1で初期化するとtwoの値は2となる
const two = 1 + 1;
console.log(two);
実行結果
2

減算演算子 (-)

[編集]

減算演算子(げんざんえんざんし、げんさんえんざんし、subtraction operator)は-です[2]

変数minus_oneを0-1で初期化するとminus_oneの値は-1となる
const minus_one = 0 - 1;
console.log(minus_one);
実行結果
-1

乗算演算子 (*)

[編集]

乗算演算子(じょうざんえんざんし、じょうさんえんざんし、multiplication operator)は*です。

const four = 2 * 2; // 変数fourを2×2で初期化するとfourは4となる
console.log(four); // 4

除算演算子 (/)

[編集]

除算演算子(じょざんえんざんし、じょさんえんざんし、division operator)は/です。

const one_half = 1 / 2; // 変数one_halfを1÷2で初期化するとone_halfは0.5となる
console.log(one_half); // 0.5

ゼロ除算(ゼロじょざん、ゼロじょさん、division by zero)は例外ではなくInfinity(あるいは-Infinity)を返します。 BigInt 同士のゼロ除算は RangeError となります。

console.log( 1 / 0 ); // Infinity
console.log( -2 / 0 ); // -Infinity
console.log( 3 /-0 ); // -Infinity
console.log( -3 /-0 ); // Infinity
console.log( 1n / 0n ); // RangeError: Division by zero

除数・被除数ともゼロの除算はNaNを返します。 BigInt 同士の除数・被除数ともゼロの除算は RangeError となります。

console.log( 0 / 0 ); // NaN
console.log( 0n / 0n ); // RangeError: Division by zero

剰余演算子 (%)

[編集]

剰余演算子(じょうよえんざんし、REMAINDER operator)は%です。割り算の余りを求めます。

const one = 10 % 3; // 10÷3は3余り1なので変数oneは1となる
console.log(one); // 1

結果は必ず左オペランドの被除数(割られる数)と同じ符号になります。

const minus_one = -10 % 3;
console.log(minus_one); // -1

ゼロ剰余(ゼロじょうよ、REMAINDER by zero)は例外ではなくNaNを返します。 BigInt 同士の剰余は RangeError となります。

console.log( 10 % 0 ); // NaN
console.log( 10n % 0n ); // RangeError: Division by zero

a % ba - b * Math.trunc(a / b)と等価です。 Perl や Ruby のようにa - b * Math.floor(a / b)と等価ではありません。これは IEEE754 の Remainder に定義された挙動で C 言語の libm にある fmod() と同じ動作です。

const remainder = (a,b) => (a - b * Math.trunc(a/b));
for (let i = -1.2; i <= 1.2; i += 1.2)
  for (let j = -1.3; j <= 1.3; j += 1.3)
    console.log(`${i} % ${j}= ${i%j} (=${remainder(i,j)}), ${i} / ${j} = ${i / j}`);
/*
 -1.2 % -1.3= -1.2 (=-1.2), -1.2 / -1.3 = 0.923076923076923
 -1.2 % 0= NaN (=NaN), -1.2 / 0 = -Infinity
 -1.2 % 1.3= -1.2 (=-1.2), -1.2 / 1.3 = -0.923076923076923
 0 % -1.3= 0 (=0), 0 / -1.3 = 0
 0 % 0= NaN (=NaN), 0 / 0 = NaN
 0 % 1.3= 0 (=0), 0 / 1.3 = 0
 1.2 % -1.3= 1.2 (=1.2), 1.2 / -1.3 = -0.923076923076923
 1.2 % 0= NaN (=NaN), 1.2 / 0 = Infinity
 1.2 % 1.3= 1.2 (=1.2), 1.2 / 1.3 = 0.923076923076923
*/

除数は浮動小数点数でもかまいません(元々 Number は64ビット倍精度浮動小数点数です)。

const theta = Math.PI / 4;
console.log(Math.sin(theta) === Math.sin(theta % (2 * Math.PI))); // true

単項プラス演算子 +()

[編集]

単項プラス演算子(たんこうプラスえんざんし、unary plus operator)は式を評価し、数値でなかった場合は暗黙な変換に従い数値に変換します。

const two = "2";
console.log(+two); // 2

単項プラスと暗黙の型変換

[編集]
const ary = [undefined, null, false, true, 0, 1, "", "1", [], [2]]
const json = ary.map(x => x === undefined ? "undefined" : JSON.stringify(x))
let s = ""
s += `{| class="wikitable"
|+ 単項プラスと暗黙の型変換
! ${json.join("!!")}
`
  s += `|-
| ${ary.map(x => `${+x}:${typeof(+x)}` ).join("||")}
`
s += `|}`
console.log(s)
単項プラスと暗黙の型変換
undefined null false true 0 1 "" "1" [] [2]
NaN:number 0:number 0:number 1:number 0:number 1:number 0:number 1:number 0:number 2:number

単項マイナス演算子 -()

[編集]

単項マイナス演算子(たんこうマイナスえんざんし、unary negation operator)は符号を反転させた数(反数)を返します。符号反転演算子(ふごうはんてんえんざんし)、算術否定演算子(さんじゅつひていえんざんし)などという言い方をする人もいます。

const one = 1;
console.log(-one); // -1

a * -1と似ていますが BigInt が渡されても TypeError とはならない点が異なります。

インクリメント演算子 (++)

[編集]

インクリメント演算子(インクリメントえんざんし、increment operator)は変数の値を1増やします。

let x = 0;
x++;
console.log(x); // 1

インクリメント演算子は後置++すると増やす前の値を返し、

let x = 0;
const y = x++;
console.log(y); // 0
console.log(x); // 1

++前置すると増やした後の値を返します。

let x = 0;
const y = ++x;
console.log(y); // 1
console.log(x); // 1

複数のインクリメント演算子を同時に適用することはできません。

let x = 0;
(x++)++; // SyntaxError: Invalid left-hand side expression in postfix operation

x++x += 1、すなわちx = x + 1と等価です。インクリメント演算子は変数の値を増加させるので、1++のようにリテラル(定数)に対して適用することはできません。

デクリメント演算子 (--)

[編集]

デクリメント演算子(デクリメントえんざんし、decrement operator)は変数の値を1減らします。

let x = 0;
x--;
console.log(x); // -1

デクリメント演算子は後置--すると減らす前の値を返し、

let x = 0;
const y = x--;
console.log(y); // 0
console.log(x); // -1

--前置すると減らした後の値を返します。

let x = 0;
const y = --x;
console.log(y); // -1
console.log(x); // -1

複数のデクリメント演算子を同時に適用することはできません。

let x = 0;
(x--)--; // SyntaxError: Invalid left-hand side expression in postfix operation

x--x -= 1、すなわちx = x - 1と等価です。デクリメント演算子は変数の値を減少させるので、1--のようにリテラル(定数)に対して適用することはできません。

冪乗演算子 (**)

[編集]

冪乗演算子(べきじょうえんざんし)は、第1オペランドを第2オペランドの累乗した結果を返します。Math.pow と同等ですが、オペランドとして BigInt を受け入れることができます。

const power = 2 ** 10;
console.log(power); // 1024

なお、^はビットごとのXOR演算子です。

ビット演算子

[編集]

ビット演算子(ビットえんざんし、bitwise operator)は、ビット演算の演算子です。ビット演算とは数値を32ビット整数変換し、各ビットに対して行う演算のことです。

JavaScriptのビット演算子
演算子 意味
a & b ビットごとのAND
a | b ビットごとのOR
a ^ b ビットごとのXOR
~a ビットごとのNOT(補数)
a << b 左シフト
a >> b 右シフト
a >>> b 符号なし右シフト

a >>> bは捨てられたビットの分だけ左から0を詰めます。 ' >>> は BigInt に適用すると TypeError になります。 ビット演算子は算術演算子よりも優先順位が低いことに注意してください。

文字列連結演算子

[編集]

+は加算演算子であると同時に、文字列連結演算子(もじれつれんけつえんざんし、string concatenation operator)でもあります。

const str = "Wiki" + "books";
console.log(str); // "Wikibooks"

文字列と数値を連結すると、文字列の方が強いので数値は文字列に変換されます。

const str = "JavaScript " + 1.5;
console.log(str); // "JavaScript 1.5"

これは足し算をしようとして文字列がまじっていると厄介なことになります。

const one = "1";
const two = one + 1;
console.log(two); // "11" -- console.log()メソッドではわかりにくいですが、2文字の文字列です。

文字列の連結よりも数値の加算を優先させるには、文字列を数値に変換した上で加算しなければなりません。文字列を数値に変換するには、教科書的にはparseInt関数やparseFloat関数、Numberオブジェクトのコンストラクタなどを使いますが、

const one = "1";
const two = parseInt(one) + 1;
console.log(two); // 2

一般的には単項プラス演算子を使用した方が高速です。

const one = "1";
const two = +one + 1;
console.log(two); // 2

ほかにも1を掛ける (one * 1)、0を引く (one - 0))などの方法があります。 これらの演算子は数値にしか適用できないので、処理系が被演算子を自動的に数値に変換(暗黙的な型変換)するためです。

かつてこの本で、0で符号なし右シフトをする (one >>> 0あるいは 補数の補数を得る(~~one)文字列を数値に変換する方法として紹介されていましたが、前者は32ビット符号なし整数に、後者は32ビット符号付き整数への変換となり浮動小数点数を表す文字列に適用すると、、

"3.14" >>> 0  === 3
"-3.14" >>> 0 === 4294967293
~~"3.14"  === 3
~~"-3.14" === -3

の様になります。興味深い挙動ですが文字列を数値に変換する方法としては妥当とは言えません。

加算と暗黙の型変換

[編集]

加算と暗黙の型変換の結果を表にしました。

const ary = [undefined, null, false, true, 0, 1, "", "1", [], [2]]
const json = ary.map(x => x === undefined ? "undefined" : JSON.stringify(x))
let s = ""
s += `{| class="wikitable"
|+ 加算と暗黙の型変換
! ${["左辺\右辺",...json].join("!!")}
`
for (const y of ary) {
  s += `|-
! ${y === undefined ? "undefined" : JSON.stringify(y)}
| ${ary.map(x => `${y + x}:${typeof(y + x)}` ).join("||")}
`
}
s += `|}`
console.log(s)
加算と暗黙の型変換
左辺\右辺 undefined null false true 0 1 "" "1" [] [2]
undefined NaN:number NaN:number NaN:number NaN:number NaN:number NaN:number undefined:string undefined1:string undefined:string undefined2:string
null NaN:number 0:number 0:number 1:number 0:number 1:number null:string null1:string null:string null2:string
false NaN:number 0:number 0:number 1:number 0:number 1:number false:string false1:string false:string false2:string
true NaN:number 1:number 1:number 2:number 1:number 2:number true:string true1:string true:string true2:string
0 NaN:number 0:number 0:number 1:number 0:number 1:number 0:string 01:string 0:string 02:string
1 NaN:number 1:number 1:number 2:number 1:number 2:number 1:string 11:string 1:string 12:string
"" undefined:string null:string false:string true:string 0:string 1:string :string 1:string :string 2:string
"1" 1undefined:string 1null:string 1false:string 1true:string 10:string 11:string 1:string 11:string 1:string 12:string
[] undefined:string null:string false:string true:string 0:string 1:string :string 1:string :string 2:string
[2] 2undefined:string 2null:string 2false:string 2true:string 20:string 21:string 2:string 21:string 2:string 22:string

この表は、二項演算子(+)と様々な値の組み合わせについて見てみました。

if文の条件式などのブーリアンコンテキストでの真理値への変換や、単項+の数値への変換は、また別の規則になります。

代入演算子

[編集]

代入演算子(だいにゅうえんざんし、assignment operator)は変数に値を代入します。代入した値を返し、結合は右から左です[3]

let x = 0;
console.log(x = 1); // 1

let a, b;
a = b = 0;

複合代入演算子

[編集]

複合代入演算子(ふくごうだいにゅうえんざんし、Compound assignment operators)は、x = x OPERATOR yの形式をx OPERATOR= yの形式に短縮表記したものです。代入演算子と同じ優先度を持ち、演算し代入した値を返し、結合は右から左です。OPERATORで1つのトークンで、OPERATOR=の間に空白を含めることはできません。 例えば、x *= yx = x * yと等価です。

let x = 1;
x += 1;   // x = x + 1
console.log(x); // 2
JavaScriptの代入演算子の短縮表記
短縮表記 等価な表記 意味
x += y x = x + y 加算代入演算子 (Addition assignment operator)
x -= y x = x - y 減算代入演算子 (Subtraction assignment operator)
x *= y x = x * y 乗算代入演算子 (Multiplication assignment operator)
x /= y x = x / y 除算代入演算子 (Division assignment operator)
x %= y x = x % y 剰余代入演算子 (Remainder assignment operator)
x **= y x = x ** y 冪乗代入演算子 (Exponentiation assignment operator)
x <<= y x = x << y 左シフト代入演算子 (Left shift assignment operator)
x >>= y x = x >> y 右シフト代入演算子 (Right shift assignment operator)
x >>>= y x = x >>> y 符号なし右シフト代入演算子 (Unsigned right shift assignment operator)
x &= y x = x & y ビット間論理積代入演算子 (Bitwise AND assignment operator)
x ^= y x = x ^ y ビット間排他的論理和代入演算子 (Bitwise XOR assignment operator)
x |= y x = x | y ビット間論理和代入演算子 (Bitwise OR assignment operator)
x &&= y x = x && y 論理積代入演算子 (Logical AND assignment operator)
x ||= y x = x || y 論理和代入演算子 (Logical OR assignment operator)
x ??= y x = x ?? y 論理Null合体代入演算子 (Logical nullish assignment operator)

分割代入

[編集]

分割代入(ぶんかつだいにゅう、Destructuring assignment)は、配列の値やオブジェクトのプロパティを個別の変数に展開することができるJavaScriptの表現方法です[4]

JavaScriptには、様々な種類の分割代入があります。以下に代表的なものを示します。

分割代入の例
// 配列の分割代入
const [a, b, c] = [1, 2, 3];
console.log(a); // => 1
console.log(b); // => 2
console.log(c); // => 3

// オブジェクトの分割代入
const person = { name: 'Alice', age: 20 };
const { name, age } = person;
console.log(name); // => 'Alice'
console.log(age); // => 20

// 別名の指定
const { name: firstName, age: years } = person;
console.log(firstName); // => 'Alice'
console.log(years); // => 20

// デフォルト値の指定
const { name: names  = 'Anonymous', age: ages = 0 } = {};
console.log(names); // => 'Anonymous'
console.log(ages); // => 0

// 関数の引数としての分割代入
function foo({ x, y }) {
  console.log(x, y);
}

const point = { x: 1, y: 2 };
foo(point); // => 1 2

// 可変長引数の受け取り
function sum(a, b, ...rest) {
  console.log(a + b);
  console.log(rest);
}

sum(1, 2, 3, 4, 5); 
// => 3
// => [3, 4, 5]
実行結果
1
2
3
Alice
20
Alice
20
Anonymous
0
1 2
3 
[ 3, 4, 5 ]

このコードは、JavaScriptにおける分割代入の様々な使い方を示しています。

最初の例では、配列の分割代入を使用して、3つの変数 abc にそれぞれ配列 [1, 2, 3] の要素を代入しています。

次に、オブジェクトの分割代入を使用して、オブジェクト person のプロパティ nameage を変数 nameage に代入しています。

その後、別名を指定してオブジェクトの分割代入を行い、変数 firstNameyearsperson オブジェクトのプロパティ nameage をそれぞれ代入しています。

次に、デフォルト値を指定してオブジェクトの分割代入を行い、空のオブジェクトから name プロパティが Anonymousage プロパティが 0 のデフォルト値を持つ変数 namesages を作成しています。

次に、関数の引数としての分割代入を示しています。 foo 関数は、オブジェクト { x, y } を引数として受け取り、そのプロパティを console.log で表示するように定義されています。この関数は、point オブジェクトを引数として呼び出され、その結果、1 2 が表示されます。

最後に、可変長引数を受け取る関数 sum を定義し、 12 を最初の2つの引数として、残りの引数を可変長引数 rest に代入しています。console.log を使用して、最初の2つの引数の合計値と残りの引数を表示します。sum(1, 2, 3, 4, 5) が呼び出されると、3[3, 4, 5] が表示されます。

論理演算子

[編集]

論理演算子(ろんりえんざんし、logical operator)とは、真偽値を返す論理的な演算子です。短絡評価副作用に注意してください[5]

論理積演算子 (&&)

[編集]

論理積演算子は、両方のオペランドが true であったら true を、それ以外は false を返します。

論理積演算子の構文

[編集]
left && right

論理和演算子 (||)

[編集]

論理和演算子は、片方または両方のオペランドが true であったら true を、それ以外は false を返します。

論理和演算子の構文

[編集]
left || right

否定演算子 (!)

[編集]

否定演算子は、オペランドを論理型に変換した後、true であったら false を、false であったら true を返します。

否定演算子の構文

[編集]
! bool

JavaScriptに排他的論理和演算子は存在しませんが、

  • Boolean(p) != Boolean(q)

と真偽値に変換した後、不一致を評価する式で実現できます。

  • !p != !q

でも可。

関係演算子

[編集]

関係演算子(かんけいえんざんし、Relational operator)とは、大小関係あるいは包含関係を比較して真偽値を返す演算子です[6]

=<=> のようなに = が先にくる関係演算子は存在しないので気をつけてください(特に => はアロー関数の構文で書き方によっては SyntaxError とならず発見困難なバグの原因になります)。大小比較は必ず手前に大なり小なり、後にイコールが来ます。

in 演算子

[編集]

in 演算子は、プロパティがオブジェクトに含まれると true を返します。for in 文の in とは違います。

in 演算子の構文

[編集]
prop in obj

instanceof 演算子

[編集]

instanceof 演算子は、コンストラクタのprototype プロパティがオブジェクトのプロトタイプ・チェーンのどこかに現れるかどうかをテストします。戻り値は、論理値です[7]

instanceof 演算子の構文

[編集]
obj1 instanceof obj2

小なり演算子

[編集]

小なり演算子は、左辺が右辺より小さいかどうかをテストします。戻り値は、論理値です。

小なり演算子の構文

[編集]
left < right

小なりイコール演算子

[編集]

小なりイコール演算子は、左辺が右辺より小さいあるいは等しいかをテストします。戻り値は、論理値です。

小なりイコール演算子の構文

[編集]
left <= right

大なり演算子

[編集]

大なり演算子は、左辺が右辺より大きいかどうかをテストします。戻り値は、論理値です。

大なり演算子の構文

[編集]
left > right

大なりイコール演算子

[編集]

大なりイコール演算子は、左辺が右辺より大きいあるいは等しいかをテストします。戻り値は、論理値です。

大なりイコール演算子の構文

[編集]
left >= right

等値演算子

[編集]

等値演算子(とうかえんざんし、equality operators)とは、比較して真偽値を返す演算子です[8]

等価演算子 (==)

[編集]

等価演算子は、左辺が右辺と等しいかをテストします。比較は暗黙の型変換の後に行われます。戻り値は、論理値です。

等価演算子の構文

[編集]
left == right

不等価演算子 (!=)

[編集]

不等価演算子は、左辺が右辺と等しくないかをテストします。比較は暗黙の型変換の後に行われます。戻り値は、論理値です。

不等価演算子の構文

[編集]
left != right

同値演算子 (===)

[編集]

同値演算子(厳密一致演算子)は、左辺が右辺と等しいかをテストします。型が異なれば直ちに不一致を返します。戻り値は、論理値です。N

同値演算子の構文

[編集]
left === right

不同値演算子 (!==)

[編集]

不同値演算子(厳密不一致演算子)は、左辺が右辺と等しくないかをテストします。型が異なれば直ちに不一致を返します。戻り値は、論理値です。

不同値演算子の構文

[編集]
left !== right
0と-0の比較
0 == -0;  // ES6 では true
0 === -0; // ES6 では true

ES6より前は 0 と -0 は一致しませんでしたが、ES6 以降は 0 と -0 は一致するようになりました。これは厳密一致についても同じです。

プロパティアクセサ

[編集]

プロパティアクセサproperty accessor)とは、オブジェクトの(メソッドを含む)プロパティにアクセスするための演算子式で、左辺値式です。

ドット記法のプロパティアクセサ

[編集]

ドット記法のプロパティアクセサは、object . propertyの構文で、.を挟んだ二項式です。 ドット記法では、propertyが識別子として有効なときにのみ使え識別子以外を用いると SyntaxError を throw します。

const object = {};
object.myName = "tom"; // 正常
object.123 = 0; // SyntaxError:
object.my-name = "lisa"; // SyntaxError:

ブラケット記法のプロパティアクセサ

[編集]

ブラケット記法のプロパティアクセサは、object [ property ]の構文で、[ ]を使った配列アクセス似の記法です。文字列の他、Symbol もキーにできます。

const object = {};
object["myName"] = "tom"; // 正常
object["123"] = 0; // 正常
object["my-name"] = "lisa"; // 正常

条件演算子

[編集]

条件が真なら式1を評価しその値を返す、条件が真でなければ式2を評価しその値を返します。

 条件 ? 式1 : 式2

カンマ演算子

[編集]

カンマで区切られた式を左から順に評価し、最後の式の値を返す

 式1, 式2, 式3, 式4, 式5 ...,式n

グループ化演算子

[編集]

グループ化演算子は、評価の優先順位を制御します。最上位の優先度を有しますが、短絡評価の影響を受けます[9]

 (  )

delete演算子

[編集]

delete演算子 はオブジェクトからプロパティを取り除きます。

delete プロパティ

関数呼び出し演算子

[編集]

関数名に続く括弧はグループ化演算子ではなく、関数呼び出しです。

 関数名 ( 引数列 )

new演算子

[編集]

new 演算子は、ユーザー定義のオブジェクト型や、コンストラクタ機能を持つ組み込みオブジェクト型のインスタンスを作成します[10]

new演算子の構文

[編集]
構文
 new コンストラクタ [ ( [ パラメータ列 ] ) ]
/*
 * function 製のコンストラクタに適用した例
 */
const T = function(x = 0) {
    this.x = x;
}
T.prototype.value = function() {
    return this.x;
}

const t = new T(42);
console.log(t.value())

/*
 * class に適用した例
 */
class C {
    constructor(x = 0) {
        this.x = x;
    }
    value() {
        return this.x;
    }
}

const c = new C(13);
console.log(c.value())
実行結果
42 
13

void 演算子

[編集]

式を評価し(結果に関わらず)undefined を返します。

 void 

yield 演算子

[編集]

yieldキーワードは、ジェネレータ機能(function*)を一時停止および再開するために使用します[11]

 yeild 

yield* 演算子

[編集]

yield*式は、別のジェネレータやイテレート可能なオブジェクトに処理を委譲します[12]

 yeild* 

typeof 演算子

[編集]

typeof演算子(タイプオブえんざんし、typeof operator)はデータ型を返します。

 typeof 
typeof 42;              // "number"
typeof "Hello, world!"; // "string"
typeof [1,2,3];         // "object"; Arrayラッパーオブジェクト
typeof new Array();     // "object"; Arrayラッパーオブジェクト
typeof new String("ab");// "object"; Stringラッパーオブジェクト
typeof new RegExp();    // "object"; RegExpラッパーオブジェクト
typeof new Set();       // "object"; Setラッパーオブジェクト
typeof new WeakSet();   // "object"; WeakSetラッパーオブジェクト
typeof new Map();       // "object"; Mapラッパーオブジェクト
typeof new WeakMap();   // "object"; WeakMapラッパーオブジェクト
typeof function(){};    // "function"
typeof true;            // "boolean"
typeof void 0;          // "undefined"
typeof null;            // "object"; ラッパーではなく互換性のための仕様
typeof 123n;            // "bigint"
typeof Symbol();        // "symbol"
typeof {};              // "object"

結合性

[編集]

同じ優先順位の演算子(下表参照)が連なった時の評価順序を結合性(けつごうせい、associativity)といいます。

左結合(ひだりけつごう、left-associative)
左から右に評価される演算
( expr1 OP1 expr2 ) OP2 expr3と解釈される
典型的には四則
右結合(みぎけつごう、right-associative)
右から左に評価される演算
expr1 OP1 ( expr2 OP2 expr3 )と解釈される
典型的には代入

たとえば、a - b - ca - (b - c)ではなく(a - b) - cと左から右に評価されるため、減算演算子は左結合です。また、a = b = c(a = b) = cではなくa = (b = c)と評価されるため、代入演算子は右結合です。インクリメント演算子++やデクリメント演算子--は、左辺値式ではないので x++ ++ とすると SyntaxErroor となり結合性は定義されません。

結合性の例題

[編集]

次の式の演算子の結合性を述べ、それに従い括弧を補ってください。

  1. typeof typeof object
  2. p == q == r
  3. a > 0 ? 1 : a < 0 ? -1 : 0
  4. a, b, c


結合性の例題の解答

[編集]
  1. 右結合:typeof ( typeof object )と解釈されます。
  2. 左結合:p == q == r( p == q ) == rと解釈されます。
  3. 右結合:a > 0 ? 1 : ( a < 0 ? -1 : 0 )と解釈される[13]
  4. 左結合:( a, b ), cと解釈されます(式の値は、c となります)。

演算子の優先順位

[編集]
JavaScriptの演算子の優先順位と結合性[14]
優先順位 演算子のタイプ 結合性 構文
21 グループ化 なし ( ... )
20 ドット記法プロパティアクセサ 左から右へ ... . ...
ブラケット記法プロパティアクセサ ... [ ... ]
new(引数リスト付き) なし new ... ( ... )
関数の呼び出し 左から右へ ... ( ... )
オプショナルチェイニング ?.
19 new (引数リストなし) 右から左へ new ...
18 後置インクリメント なし ... ++
後置 デクリメント ... --
17 ロジカルNOT (!) 右から左へ ! ...
ビット単位のNOT (~) ~ ...
単項プラス (+) + ...
単項マイナス (-) - ...
前置インクリメント なし ++ ...
前置 デクリメント -- ...
typeof 右から左へ typeof ...
void void ...
delete delete ...
await await ...
16 累乗(**) 右から左へ ... ** ...
15 乗算(*) 左から右へ ... * ...
除算(/) ... / ...
剰余(%) ... % ...
14 加算(+) 左から右へ ... + ...
減算(-) ... - ...
13 左シフト(<<) 左から右へ ... << ...
右シフト (>>) ... >> ...
符号なし右シフト (>>>) ... >>> ...
12 小さい (<) 左から右へ ... < ...
小さいか同じ (<=) ... <= ...
大きい (>) ... > ...
大きいか同じ (>=) ... >= ...
in ... in ...
instanceof ... instanceof ...
11 等式(==) 左から右へ ... == ...
不等式(!=) ... != ...
厳密な等式(===) ... === ...
厳密な不等式(!==) ... !== ...
10 ビット単位の論理積(&) 左から右へ ... & ...
9 ビット単位の排他的論理和(^) 左から右へ ... ^ ...
8 ビット単位の論理和(|) 左から右へ ... | ...
7 論理積(&&) 左から右へ ... && ...
6 論理和(||) 左から右へ ... || ...
5 Null合体 左から右へ ... ?? ...
4 条件演算子(?:) 右から左へ ... ? ... : ...
3 代入演算子 右から左へ … = …
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
… &&= …
… ||= …
… ??= …
2 yield 右から左へ yield …
yield* yield* …
1 カンマ演算子 左から右へ ... , ...

脚註

[編集]
  1. ^ ECMA-262::13.8.1 The Addition Operator ( + )
  2. ^ ECMA-262::13.8.2 The Subtraction Operator ( - )
  3. ^ ECMA-262::13.15 Assignment Operators
  4. ^ ECMA-262::13.15.5 Destructuring Assignment
  5. ^ ECMA-262::13.13 Binary Logical Operators
  6. ^ ECMA-262::13.10 Relational Operators
  7. ^ ECMA-262::13.10.2 InstanceofOperator ( V, target )
  8. ^ ECMA-262::13.11 Equality Operators
  9. ^ ECMA-262::13.2.9 The Grouping Operator
  10. ^ ECMA-262::13.3.5 The new Operator
  11. ^ ECMA-262::YieldExpression
  12. ^ ECMA-262::15.5.5 Runtime Semantics: Evaluation
  13. ^ 条件演算子は短絡評価されるので、条件式が真であった場合には第三項は評価されないです。
  14. ^ スプレッド構文は演算子ではないので含めていません。
このページ「JavaScript/演算子」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。