コンマ演算子はいつ役に立ちますか?


88

式()の「コンマ演算子」に関するこの質問,とそれに関するMDNドキュメントを読みましたが、それが役立つシナリオは考えられません。

では、コンマ演算子はいつ役に立ちますか?


2
var i, j, k;var i; var j, var k
Salman A

15
@SalmanA。,オペレーターと関係があるかどうかはわかりません。その行はでも有効ですC#が、,演算子はそこに存在しません。
–gdoronは2012

2
@SalmanA。やった。見つかりませんでした、教えてください...
–gdoronはMonicaをサポートし

5
@SalmanA a,は常に,演算子であるとは限りません(,C#では決して演算子ではありません)。したがって、C#は、構文の一部として,自由に使用,しながら、演算子が不足している可能性があります。
セスカーネギー

8
ここでの答え,は、が広く使用されていないという事実を要約していると思います(そして、aのすべての出現が,コンマ演算子であるとは限りません)。ただし、一時変数を作成せずに、それと配列を借用して、変数スワップをインラインで実行できます。との値を交換したい場合はabを実行できますa = [b][b = a,0]。これにより、電流bが配列に配置されます。2つ目[]は、プロパティアクセス表記です。アクセス指数は0、ではない割り当てる前abので、今や安全であり、bアレイ内に保持されています。で,複数の式を実行できます[]

回答:


128

以下は、自分で記述しないため、おそらくあまり役​​に立ちませんが、ミニファイアは、コンマ演算子を使用してコードを縮小できます。例えば:

if(x){foo();return bar()}else{return 1}

になります:

return x?(foo(),bar()):1

? :コンマ演算子(ある程度)では2つのステートメントを1つのステートメントとして記述できるため、この演算子を使用できるようになりました。

これ、きちんとした圧縮(ここでは39-> 24バイト)を可能にするという点で便利です。


のコンマvar a, b式内に存在しないため、コンマ演算子ではないという事実を強調したいと思います。カンマはステートメントで特別な意味を持ちます。式では、2つの変数を参照し、に評価されますが、はそうではありません。var a, bbvar a, b


3
それについてどう思いましたか?どこかで読んだ?本当に使われているのでしょうか?
–gdoronは2012

16
先日、Closure Compilerをいじって実際に何が行われるかを確認していましたが、この置換に気づきました。
pimvdb 2012年

2
コードで役立つと思う同様の使用法は、インラインifステートメントで複数の変数を割り当てることです。例:if (condition) var1 = val1, var2 = val2;個人的には、可能な限り角かっこを避けると、コードが読みやすくなると思います。
aidiakapi 2014年

2
コンマ演算子を使用するのは、式にログステートメントを追加するとき(foo =>(console.log( 'foo'、foo)、foo))、またはreduceiteratesで賢くなりすぎる場合だけです。 。(pairs.reduce((acc、[k、v])=>(acc [k] = v、acc)、{}))
JosephSikorski18年

38

コンマ演算子を使用すると、1つの式が必要な場所に複数の式を配置できます。 コンマで区切られた複数の式の結果の値は、最後のコンマで区切られた式の値になります。

複数の式が予想される状況はそれほど多くなく、コンマ演算子を使用するよりもコードを書くための混乱の少ない方法がないため、私は個人的にはあまり使用しません。興味深い可能性の1つは、forループの最後で、複数の変数をインクリメントする場合です。

// j is initialized to some other value
// as the for loop executes both i and j are incremented
// because the comma operator allows two statements to be put in place of one
for (var i = 0; i < items.len; i++, j++) {
    // loop code here that operates on items[i] 
    // and sometimes uses j to access a different array
}

ここでi++, j++は、1つの式が許可されている場所に配置できることがわかります。この特定のケースでは、複数の式が副作用に使用されるため、複合式が最後の式の値をとることは問題ではありませんが、実際に問題になる場合もあります。


38

コンマ演算子は、Javascriptで関数型コードを書くときによく役立ちます。

しばらく前にSPA用に作成した次のようなコードを考えてみましょう。

const actions = _.chain(options)
                 .pairs() // 1
                 .filter(selectActions) // 2
                 .map(createActionPromise) // 3
                 .reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
                 .value();

これはかなり複雑でしたが、実際のシナリオでした。私が何が起こっているのかを説明している間、私と一緒に耐えてください、そしてその過程でコンマ演算子の主張をしてください。


これは、アンダースコアのチェーンを使用して

  1. 使用して、この関数に渡されるオプションのすべてを離れて取ることpairs になりますどの{ a: 1, b: 2}[['a', 1], ['b', 2]]

  2. このプロパティペアの配列は、システム内の「アクション」と見なされるものによってフィルタリングされます。

  3. 次に、配列の2番目のインデックスは、そのアクションを表すpromiseを返す関数に置き換えられます(を使用してmap

  4. 最後に、を呼び出すと、reduce各「プロパティ配列」(['a', 1])がマージされて最終オブジェクトに戻ります。

最終結果はoptions引数の変換バージョンであり、適切なキーのみが含まれ、その値は呼び出し元の関数によって消費可能です。


ただ見て

.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})

reduce関数は、空の状態オブジェクト、stateで始まり、キーと値を表す各ペアについて、キーと値のペアにstate対応するオブジェクトにプロパティを追加した後、関数は同じオブジェクトを返します。ECMAScript 2015の矢印関数構文により、関数本体は式であり、その結果、コンマ演算子を使用すると、簡潔で便利な「反復」関数を使用できます。

個人的には、ECMAScript 2015 + Arrow Functionsを使用してより機能的なスタイルでJavascriptを記述しているときに、多くのケースに遭遇しました。そうは言っても、矢印関数に遭遇する前(質問の執筆時など)は、意図的な方法でコンマ演算子を使用したことはありませんでした。


2
これは、プログラマーがコンマ演算子をいつどのように使用できるかに関して、本当に役立つ唯一の答えです。特にreduce
hgoebl 2018

1
ES6 +では、これが受け入れられる答えになるはずです。
Ardee Aram

いい答えですが、もう少し読みやすいものを提案する場合は、次のようにします.reduce((state, [key, value]) => (state[key] = value, state), {})。そして、これは答えの目的を損なうことを理解していますが.reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})、コンマ演算子の必要性を完全に排除するでしょう。
パトリックロバーツ

Object.assignはおそらく最近ではもっと慣用的であるか、または単にspread演算子でさえありますが、当時広く使用されていたかどうかはわかりません。また、コンマ演算子はもう少しわかりにくいですが、データセットが非常に大きい状況では、これによって生成されるガベージが大幅に少なくなる可能性があることも指摘しておきます。破壊することは確かに読みやすさを助けるでしょう!
シンス

18

コンマ演算子のもう1つの使用法は、純粋に便宜のために、replまたはコンソールで気にしない結果を非表示にすることです。

たとえば、担当者myVariable = aWholeLotOfTextまたはコンソールで評価すると、割り当てたばかりのすべてのデータが出力されます。これはページとページである可能性があり、表示したくない場合は、代わりに評価することができmyVariable = aWholeLotOfText, 'done'、repl / consoleは「done」と出力します。

Orielは、カスタマイズされた機能や機能によってこれが役立つ可能性があることを正しく指摘していますtoString()get()


1
ハ、とてもいいアイデアです!(最後に、ほとんどすべての回答とは異なり、実際に質問に回答する回答{および、表示するには20Kの評判が必要な3つの削除された回答...})
gdoronはMonicaをサポートしています2016

1
割り当てられた値がオブジェクトの場合、コンソールはそれを適切に表示しようとする場合があります。これを行うには、たとえばゲッターを呼び出すと、オブジェクトの状態が変わる可能性があります。カンマを使用すると、これを防ぐことができます。
オリオール

@ Oriol-いいね!あなたは完全に正しいです。どういうわけか、これが潜在的に有用であると少しがっかりします:)
Julian de Bhal 2016

13

コンマ演算子はJavaScriptに固有のものではなく、CやC ++などの他の言語で使用できます。二項演算子として、これは、一般に式である第1オペランドに、第2オペランドに必要な望ましい副作用がある場合に役立ちます。ウィキペディアからの一例:

i = a += 2, a + b;

もちろん、2行の異なるコードを記述できますが、コンマを使用することも別のオプションであり、場合によっては読みやすくなります。


1
善の定義は人によって異なるかもしれませんが、これを代替案と考えてください。ただし、カンマを使用しなければならない例は見つかりません。別の同様のものは三項?:演算子です。これは常にif-elseに置き換えることができますが、場合によっては?:if-elseよりも読みやすいコードになります。同じ概念がコンマにも当てはまります。
taskinoor 2012年

ところで、変数宣言でコンマを使用したり、ループで複数の変数を初期化したりすることは考えていません。そのような場合、コンマの方がほとんどです。
taskinoor 2012年

2
これは紛らわしいaf ... wtfに見えます。
Timmerz 2016

6

私はFlanaganに同意しません、そして、コンマは本当に便利で、特にあなたが何をしているのかを知っているとき、より読みやすくエレガントなコードを書くことを可能にする、と言います:

ここにあります大幅に詳細な記事コンマの使用上には:

デモンストレーションの証明のためのそこからのいくつかの例:

function renderCurve() {
  for(var a = 1, b = 10; a*b; a++, b--) {
    console.log(new Array(a*b).join('*'));
  }
}

フィボナッチジェネレーター:

for (
    var i=2, r=[0,1];
    i<15;
    r.push(r[i-1] + r[i-2]), i++
); 
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377

jQuery.parent()関数の類似物である最初の親要素を見つけます。

function firstAncestor(el, tagName) {
    while(el = el.parentNode, el && (el.tagName != tagName.toUpperCase()));
    return el;
}

//element in http://ecma262-5.com/ELS5_HTML.htm
var a = $('Section_15.1.1.2'); 

firstAncestor(a, 'div'); //<div class="page">

7
どれかがもっと読みやすいと言えるかどうかはわかりませんが、確かにかなりスパイシーなので+1
Chris Marisic 2014

1
最後の例のwhileループではコンマは必要ありませんが、while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))そのコンテキストでは問題ありません。
PitaJ 2016

5

それ以外の実用的な使用法は見つかりませんでしたが、JamesPadolseyがwhileループでIE検出にこの手法をうまく使用しているシナリオを次に示します。

var ie = (function(){

    var undef,
        v = 3,
        div = document.createElement('div'),
        all = div.getElementsByTagName('i');

    while ( // <-- notice no while body here
        div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
        all[0]
    );

    return v > 4 ? v : undef;

}());

これらの2行は実行する必要があります:

div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]

そして、コンマ演算子の内部では、どちらも評価されますが、何らかの方法でそれらを別々のステートメントにすることもできます。


3
これはdo-whileループであった可能性があります。
ケーシーチュー

5

JavaScriptで、コンマ演算子を使用して間接的に関数を呼び出すことができる「奇妙な」ことがあります。

ここに長い説明があります: JavaScriptでの間接関数呼び出し

この構文を使用することにより:

(function() {
    "use strict";
  
    var global = (function () { return this || (1,eval)("this"); })();
    console.log('Global === window should be true: ', global === window);
  
    var not_global = (function () { return this })();
    console.log('not_global === window should be false: ', not_global === window);
  
  }());

eval直接呼び出された場合と間接的に呼び出された場合では動作が異なるため、グローバル変数にアクセスできます。


4

このようなヘルパーを作成するときに、コンマ演算子が最も役立つことがわかりました。

const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);

カンマは||のいずれかに置き換えることができます。または&&ですが、関数が何を返すかを知る必要があります。

それよりも重要なのは、コンマ区切り文字が意図を伝えることです。コード左オペランドの評価を気にしませんが、代替手段には別の理由がある場合があります。これにより、理解とリファクタリングが容易になります。関数の戻り値の型が変更されても、上記のコードは影響を受けません。

当然、他の方法でも同じことを達成できますが、それほど簡潔ではありません。||の場合 &&は一般的な使用法の場所を見つけたので、コンマ演算子も同様です。


Ramda \ Lodashが行うことと同様ですtapramdajs.com/docs/#tap)。基本的に、副作用を実行してから初期値を返します。関数型プログラミングで非常に便利です:)
avalanche119年

1

私がそれを使用することになった1つの典型的なケースは、オプションの引数解析中です。引数の解析が関数本体を支配しないように、読みやすく簡潔になっていると思います。

/**
 * @param {string} [str]
 * @param {object} [obj]
 * @param {Date} [date]
 */
function f(str, obj, date) {
  // handle optional arguments
  if (typeof str !== "string") date = obj, obj = str, str = "default";
  if (obj instanceof Date) date = obj, obj = {};
  if (!(date instanceof Date)) date = new Date();

  // ...
}

私自身は好きではありませんが、これは、私が完全に正気でないと思わずに、個々の表現ステートメントの同等のリストよりも読みやすさの点で優れていると私が思うと誰もが考えている唯一の例です。
セミコロン2015年

1

配列があるとしましょう:

arr = [];

pushその配列にアクセスするとき、pushの戻り値、つまり配列の新しい長さに関心があることはめったになく、配列自体に関心があります。

arr.push('foo')  // ['foo'] seems more interesting than 1

コンマ演算子を使用すると、配列にプッシュし、配列をコンマの最後のオペランドとして指定し、その結果(配列自体)を後続の配列メソッド呼び出し(一種の連鎖)に使用できます。

(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]

-2

コンマ演算子を使用できるもう1つの領域は、コードの難読化です。

開発者が次のようなコードを書いたとしましょう。

var foo = 'bar';

今、彼女はコードを難読化することにしました。使用するツールによって、コードが次のように変更される場合があります。

var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'

デモ: http //jsfiddle.net/uvDuE/


1
@gdoron C ++のコンマ演算子については、この回答stackoverflow.com/a/17903036/363573をご覧ください。難読化に関するJamesKanzeのコメントに気付くでしょう。
ステファン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.