쉼표 연산자는 언제 유용합니까?


88

식 ( ) 의 "쉼표 연산자"에 대한 질문 ,과 이에 대한 MDN 문서 를 읽었 지만 유용한 시나리오를 생각할 수 없습니다.

그렇다면 쉼표 연산자는 언제 유용할까요?


2
var i, j, k;var i; var j, var k?
Salman A 2012 년

15
@SalmanA. ,운영자 와 관련이 있는지 확실하지 않습니다 . 그 줄도 유효 C#하지만 ,연산자는 존재하지 않습니다.
gdoron 모니카 지원하고

2
@SalmanA. 내가했다. 찾지 못했습니다. 계몽 해주세요 ...
gdoron은 Monica를 지원

5
@SalmanA a ,는 항상 ,연산자 가 아니며 ,C # 의 연산자 가 아닙니다 . 따라서 C #은 구문의 일부로 ,자유롭게 사용하면서 연산자 가 부족할 수 있습니다 ,.
Seth Carnegie 2012 년

8
나는 여기에 대한 대답 ,이 널리 사용되지 않는다는 사실을 요약했다고 생각합니다 (그리고 모든 a ,가 쉼표 연산자는 아닙니다 ) . 그러나 임시 변수를 만들지 않고 인라인으로 변수 스왑을 수행하기 위해 그것을 빌릴 수 있습니다. a및 의 값을 바꾸고 싶다면 b할 수 있습니다 a = [b][b = a,0]. 이것은 전류 b를 배열에 배치합니다 . 두 번째 []는 속성 액세스 표기법입니다. 액세스 된 인덱스는 0이지만에 할당 a하기 전에는 아닙니다. 이 인덱스 는 Array에 유지 b되므로 이제 안전 b합니다. 을 ,사용하면 [].

답변:


128

다음은 직접 작성하지 않기 때문에 유용하지 않을 수 있지만 축소자는 쉼표 연산자를 사용하여 코드를 축소 할 수 있습니다. 예를 들면 :

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

될 것입니다 :

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

? :(어느 정도) 콤마 연산자는 두 문장 한 문장으로 기입 할 수 있기 때문에 운전자는 현재 이용 될 수있다.

이것은 이다 (-> 24 여기 바이트 39)는 몇 가지 참신한 압축 할 수 있다는 점에서 유용하다.


나는 쉼표 var a, b표현식 내에 존재하지 않기 때문에 쉼표 연산자 가 아니라는 사실을 강조하고 싶습니다 . 쉼표는 명령문 에서 특별한 의미를 갖습니다 . 식에서 두 변수를 참조 할 것이고, 평가에 대한 경우하지 않다 .var a, bbvar a, b


3
그것에 대해 어떻게 생각 했습니까? 어디서 읽었나요? 실제로 사용되고 있습니까?
gdoron 모니카 지원하고있다

16
지난번에 Closure Compiler 가 실제로 어떤 일을하는지 확인하기 위해 엉망이되었고 ,이 대체물을 발견했습니다.
pimvdb

2
코드에서 유용하다고 생각하는 유사한 용도는 인라인 if 문에 여러 변수를 할당하는 것입니다. 예를 들어, if (condition) var1 = val1, var2 = val2;개인적으로 가능한 한 대괄호를 피하면 코드가 더 읽기 쉬워 진다고 생각합니다.
Aidiakapi 2014 년

2
쉼표 연산자를 사용하는 유일한 경우는 식 (foo => (console.log ( 'foo', foo), foo))에 로그 문을 추가 할 때이거나 반복 횟수를 줄여 너무 영리 해지면 . (pairs.reduce ((acc, [k, v]) => (acc [k] = v, acc), {}))
Joseph Sikorski

38

쉼표 연산자를 사용하면 하나의 표현식이 예상되는 위치에 여러 표현식을 넣을 수 있습니다. 쉼표로 구분 된 여러 표현식의 결과 값은 마지막 쉼표로 구분 된 표현식의 값이됩니다.

두 개 이상의 표현식이 예상되는 상황이 많지 않고 쉼표 연산자를 사용하는 것보다 코드를 작성하는 데 덜 혼란스러운 방법이 없기 때문에 개인적으로 자주 사용하지 않습니다. 한 가지 흥미로운 가능성은 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++하나의 표현이 허용되는 곳에 놓을 수 있음을 알 수 있습니다. 이 특별한 경우에는 여러 표현이 부작용에 사용되므로 복합 표현이 마지막 표현의 값을 취하는 것은 중요하지 않지만 실제로 중요한 다른 경우가 있습니다.


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();

이것은 상당히 복잡하지만 실제 시나리오였습니다. 무슨 일이 일어나고 있는지 설명하고 그 과정에서 Comma Operator에 대한 사례를 만드는 동안 저를 참아주십시오.


이것은 Underscore 의 연결을 사용 하여

  1. 사용하여이 함수에 전달 된 모든 옵션을 분해 pairs 설정되는 { a: 1, b: 2}으로[['a', 1], ['b', 2]]

  2. 이 속성 쌍 배열은 시스템에서 '작업'으로 간주되는 항목으로 필터링됩니다.

  3. 그런 다음 배열의 두 번째 인덱스는 해당 작업을 나타내는 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

1
ES6 +에서는 이것이 허용되는 대답이어야합니다.
Ardee Aram

좋은 대답이지만 약간 더 읽기 쉬운 것을 제안 할 수 있다면 : .reduce((state, [key, value]) => (state[key] = value, state), {}). 그리고 나는 이것이 대답의 목적을 무너 뜨리지 만 .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})쉼표 연산자의 필요성을 완전히 제거 한다는 것을 알고 있습니다.
Patrick Roberts

Object.assign이 요즘에는 아마도 더 관용적이거나 심지어 스프레드 연산자 일 수도 있지만, 그 당시 널리 사용되었는지는 모르겠습니다. 또한 쉼표 연산자가 조금 더 모호하지만 데이터 집합이 매우 큰 상황에서 쓰레기를 훨씬 적게 생성 할 수 있음을 지적합니다. 구조화는 확실히 가독성에 도움이 될 것입니다!
Syynth

18

쉼표 연산자의 또 다른 용도는 순전히 편의상 repl 또는 console에서 신경 쓰지 않는 결과를 숨기는 것입니다.

예를 들어, myVariable = aWholeLotOfTextrepl 또는 console에서 평가 하면 방금 할당 한 모든 데이터가 인쇄됩니다. 이것은 페이지와 페이지 일 수 있으며,보고 싶지 않은 경우 대신 평가할 수 myVariable = aWholeLotOfText, 'done'있으며 repl / console은 'done'을 인쇄합니다.

Oriel은 사용자 정의 toString()또는 get()기능이이를 유용하게 만들 수 있다고 올바르게 지적 합니다.


1
하, 아주 좋은 생각이야! (마지막으로 거의 모든 답변과 달리 질문에 실제로 답변하는 답변 {그리고 확인하려면 20K 평판이 필요한 3 개의 삭제 된 답변 ...})
gdoron은 Monica를 지원

1
할당 된 값이 객체 인 경우 콘솔은이를 멋지게 표시하려고 할 수 있습니다. 이를 위해 객체의 상태를 변경할 수있는 getter를 호출 할 수 있습니다. 쉼표를 사용하면이를 방지 할 수 있습니다.
Oriol

@Oriol-좋아요! 당신 말이 맞아요. 어떻게 든이 그냥 조금 :) 실망 비트 잠재적으로 유용한 Feel로 인
줄리안 드 Bhal

13

쉼표 연산자는 JavaScript에만 국한되지 않으며 C 및 C ++와 같은 다른 언어로도 사용할 수 있습니다 . 이항 연산자로서 이것은 일반적으로 표현식 인 첫 번째 피연산자가 두 번째 피연산자에 필요한 부작용을 가질 때 유용합니다. 위키 백과의 한 예 :

i = a += 2, a + b;

분명히 두 줄의 코드를 작성할 수 있지만 쉼표를 사용하는 것은 또 다른 옵션이며 때로는 더 읽기 쉽습니다.


1
선의 정의는 사람마다 다를 수 있지만 이것을 대안으로 생각하십시오. 그러나 쉼표를 사용해야하는 예를 찾을 수 없습니다. 또 다른 유사한 것은 삼항? : 연산자입니다. 그것은 항상 if-else로 대체 될 수 있지만 때때로? :는 if-else보다 더 읽기 쉬운 코드를 만듭니다. 쉼표에도 동일한 개념이 적용됩니다.
taskinoor

BTW, 변수 선언에 쉼표를 사용하거나 루프에서 여러 변수를 초기화하는 것을 고려하지 않습니다. 이 경우 쉼표가 대부분 더 좋습니다.
taskinoor

2
이것은 혼란스러워 보입니다.
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
나는 그 중 하나가 말할 것입니다 있는지 확실하지 않습니다 더 읽기 하지만 그렇게 꽤 깔끔한 확실히 하나의
크리스 Marisic

1
마지막 예제의 while 루프에는 쉼표가 필요하지 않으며 while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))해당 컨텍스트에서는 괜찮습니다.
PitaJ

5

나는 그것 이외의 실용적인 사용을 찾지 못했지만 James Padolsey 가 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;

}());

다음 두 줄은 실행해야합니다.

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

그리고 쉼표 연산자 내부에서 둘 다 평가되지만 어떻게 든 별도의 명령문을 만들 수 있습니다.


3
이것은 수 있었다 do- while루프.
Casey Chu

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가 수행하는 작업과 유사합니다 tap( ramdajs.com/docs/#tap ). 기본적으로 부작용을 실행 한 다음 초기 값을 반환합니다. 함수형 프로그래밍에 매우 유용합니다. :)
avalanche1

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();

  // ...
}

내가 그것을 좋아하지는 않지만, 이것이 내가 완전히 미쳤다고 생각하지 않고 개별 표현 진술의 동등한 목록보다 가독성이 더 좋다고 말할 수 있다고 생각하는 유일한 예입니다.
세미콜론

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

쉼표 연산자를 사용할 수있는 또 다른 영역은 Code Obfuscation 입니다.

개발자가 다음과 같은 코드를 작성한다고 가정 해 보겠습니다.

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 . 난독 화에 대한 James Kanze의 의견을 볼 수 있습니다.
Stephan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.