JavaScript

カンマ演算子という厄介者(?)

More than 1 year has passed since last update.

JavaScriptにはカンマ演算子 , という演算子があります。配列やオブジェクト、関数の引数などの区切り記号としてのカンマとは異なるものです。
この演算子の特性を知っておかないと思わぬ落とし穴があるかもしれません。

カンマ演算子 - JavaScript | MDN

カンマ演算子の性質

カンマ演算子は左のオペランド(被演算子、簡単に言えば変数や関数といったまとまり)から右へ順に 評価(実行・処理)していく演算子で、最後(右端)のオペランドの結果を返します

// このカンマはただの区切り
const
  FOO = 'foo',
  BAR = 'bar',
  BAZ = 'baz';

// 区切りと区別するために括弧で囲む
let result = (FOO, BAR, BAZ);
console.log(result);  // baz

// 関数の引数で使う場合は引数の区切りと区別するために括弧で囲む
console.log((FOO, BAZ, BAR));  // bar

// このように書くと代入処理が優先される
result = FOO, BAR, BAZ;
console.log(result);  // foo

// このように書くとカンマ演算子が優先される
result = (FOO, BAR, BAZ);
console.log(result);  // baz

なんかややこしい

カンマ演算子が多分役に立つところ

for 文とかでたまーに役に立つときもあるかもしれません。

forを使って配列をマージするやつ
const
  ABCD = ['a', 'b', 'c', 'd'],
  EFGH = ['e', 'f', 'g', 'h'];

let i, j;

for (i = ABCD.length, j = 0; j < EFGH.length; i++, j++) {
  ABCD[i] = EFGH[j];
}

console.log(ABCD);
// ["a", "b", "c", "d", "e", "f", "g", "h"]

いい例が思いつかずにこんな回りくどい例ですが、i = abcd.length, j = 0;i++, j++ の部分の , がカンマ演算子です。
他にもいい例があるかもしれない。

カンマ演算子はややこしい

例えばこれはどうでしょう。

const
  FOO = 'foo',
  BAR = 'bar';

let temp;

function fooBar(arg1, arg2) {
  return arg1, arg2;
}

if (FOO === 'foo', BAR === 'foo') {
  console.log('1');
}

if (BAR === 'foo', FOO === 'foo') {
  console.log('2');
}

if (fooBar(FOO, BAR) === fooBar((FOO, BAR))) {
  console.log('3');
}

switch (FOO) {
  case 'foo', 'bar':
    console.log('4');
    break;

  case 'bar', 'foo':
    console.log('5');
    break;

  default:
    console.log('6');
}

temp = '';
if (temp = FOO, BAR, temp === 'foo') {
  console.log('7');
}

temp = '';
if (temp = (FOO, BAR), temp === 'foo') {
  console.log('8');
}

temp = '';
if ((temp = FOO, BAR), temp === 'foo') {
  console.log('9');
}

結果は

2
5
7
9

最後(右端)のオペランドの結果を返すことを考えると簡単ですが、一見とてもわかりづらい。
配列や関数などで使うとただの区切り文字なのかそうでないのかの区別がつきにくいですね。


カンマ演算子って微妙な立ち位置ですが、JavaScriptのコード圧縮で活躍するぐらいでしょうか。