식 ( ) 의 "쉼표 연산자"에 대한 이 질문 ,
과 이에 대한 MDN 문서 를 읽었 지만 유용한 시나리오를 생각할 수 없습니다.
그렇다면 쉼표 연산자는 언제 유용할까요?
,
운영자 와 관련이 있는지 확실하지 않습니다 . 그 줄도 유효 C#
하지만 ,
연산자는 존재하지 않습니다.
,
는 항상 ,
연산자 가 아니며 ,
C # 의 연산자 가 아닙니다 . 따라서 C #은 구문의 일부로 ,
자유롭게 사용하면서 연산자 가 부족할 수 있습니다 ,
.
,
이 널리 사용되지 않는다는 사실을 요약했다고 생각합니다 (그리고 모든 a ,
가 쉼표 연산자는 아닙니다 ) . 그러나 임시 변수를 만들지 않고 인라인으로 변수 스왑을 수행하기 위해 그것을 빌릴 수 있습니다. a
및 의 값을 바꾸고 싶다면 b
할 수 있습니다 a = [b][b = a,0]
. 이것은 전류 b
를 배열에 배치합니다 . 두 번째 []
는 속성 액세스 표기법입니다. 액세스 된 인덱스는 0
이지만에 할당 a
하기 전에는 아닙니다. 이 인덱스 는 Array에 유지 b
되므로 이제 안전 b
합니다. 을 ,
사용하면 []
.
답변:
다음은 직접 작성하지 않기 때문에 유용하지 않을 수 있지만 축소자는 쉼표 연산자를 사용하여 코드를 축소 할 수 있습니다. 예를 들면 :
if(x){foo();return bar()}else{return 1}
될 것입니다 :
return x?(foo(),bar()):1
? :
(어느 정도) 콤마 연산자는 두 문장 한 문장으로 기입 할 수 있기 때문에 운전자는 현재 이용 될 수있다.
이것은 이다 (-> 24 여기 바이트 39)는 몇 가지 참신한 압축 할 수 있다는 점에서 유용하다.
나는 쉼표 var a, b
가 표현식 내에 존재하지 않기 때문에 쉼표 연산자 가 아니라는 사실을 강조하고 싶습니다 . 쉼표는 명령문 에서 특별한 의미를 갖습니다 . 식에서 두 변수를 참조 할 것이고, 평가에 대한 경우하지 않다 .var
a, b
b
var a, b
if (condition) var1 = val1, var2 = val2;
개인적으로 가능한 한 대괄호를 피하면 코드가 더 읽기 쉬워 진다고 생각합니다.
쉼표 연산자를 사용하면 하나의 표현식이 예상되는 위치에 여러 표현식을 넣을 수 있습니다. 쉼표로 구분 된 여러 표현식의 결과 값은 마지막 쉼표로 구분 된 표현식의 값이됩니다.
두 개 이상의 표현식이 예상되는 상황이 많지 않고 쉼표 연산자를 사용하는 것보다 코드를 작성하는 데 덜 혼란스러운 방법이 없기 때문에 개인적으로 자주 사용하지 않습니다. 한 가지 흥미로운 가능성은 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++
하나의 표현이 허용되는 곳에 놓을 수 있음을 알 수 있습니다. 이 특별한 경우에는 여러 표현이 부작용에 사용되므로 복합 표현이 마지막 표현의 값을 취하는 것은 중요하지 않지만 실제로 중요한 다른 경우가 있습니다.
쉼표 연산자는 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에 대한 사례를 만드는 동안 저를 참아주십시오.
사용하여이 함수에 전달 된 모든 옵션을 분해 pairs
설정되는 { a: 1, b: 2}
으로[['a', 1], ['b', 2]]
이 속성 쌍 배열은 시스템에서 '작업'으로 간주되는 항목으로 필터링됩니다.
그런 다음 배열의 두 번째 인덱스는 해당 작업을 나타내는 promise를 반환하는 함수로 대체됩니다 (사용 map
).
마지막으로에 대한 호출 reduce
은 각 "속성 배열"( ['a', 1]
)을 최종 객체로 다시 병합 합니다.
최종 결과는 options
적절한 키만 포함하고 호출 함수에서 값을 사용할 수 있는 인수 의 변환 된 버전입니다 .
그냥보고
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})
reduce 함수가 빈 상태 객체로 시작하는 것을 볼 수 있으며 state
, 키와 값을 나타내는 각 쌍에 대해이 함수는 state
키 / 값 쌍에 해당하는 객체에 속성을 추가 한 후 동일한 객체를 반환합니다 . ECMAScript 2015의 화살표 함수 구문으로 인해 함수 본문은 표현식이며 결과적으로 쉼표 연산자는 간결하고 유용한 "반복" 함수를 허용합니다.
개인적으로 저는 ECMAScript 2015 + Arrow Functions를 사용하여보다 기능적인 스타일로 Javascript를 작성하는 동안 수많은 사례를 접했습니다. 그러나 화살표 기능을 만나기 전에 (예 : 질문 작성 당시) 쉼표 연산자를 고의적으로 사용하지 않았습니다.
reduce
.reduce((state, [key, value]) => (state[key] = value, state), {})
. 그리고 나는 이것이 대답의 목적을 무너 뜨리지 만 .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})
쉼표 연산자의 필요성을 완전히 제거 한다는 것을 알고 있습니다.
쉼표 연산자의 또 다른 용도는 순전히 편의상 repl 또는 console에서 신경 쓰지 않는 결과를 숨기는 것입니다.
예를 들어, myVariable = aWholeLotOfText
repl 또는 console에서 평가 하면 방금 할당 한 모든 데이터가 인쇄됩니다. 이것은 페이지와 페이지 일 수 있으며,보고 싶지 않은 경우 대신 평가할 수 myVariable = aWholeLotOfText, 'done'
있으며 repl / console은 'done'을 인쇄합니다.
Oriel은 † 사용자 정의 toString()
또는 get()
기능이이를 유용하게 만들 수 있다고 올바르게 지적 합니다.
쉼표 연산자는 JavaScript에만 국한되지 않으며 C 및 C ++와 같은 다른 언어로도 사용할 수 있습니다 . 이항 연산자로서 이것은 일반적으로 표현식 인 첫 번째 피연산자가 두 번째 피연산자에 필요한 부작용을 가질 때 유용합니다. 위키 백과의 한 예 :
i = a += 2, a + b;
분명히 두 줄의 코드를 작성할 수 있지만 쉼표를 사용하는 것은 또 다른 옵션이며 때로는 더 읽기 쉽습니다.
나는 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">
while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))
해당 컨텍스트에서는 괜찮습니다.
나는 그것 이외의 실용적인 사용을 찾지 못했지만 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]
그리고 쉼표 연산자 내부에서 둘 다 평가되지만 어떻게 든 별도의 명령문을 만들 수 있습니다.
do
- while
루프.
쉼표 연산자를 사용하여 간접적으로 함수를 호출하는 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
직접 호출 할 때와 간접 호출 할 때 다르게 작동 하기 때문에 전역 변수에 액세스 할 수 있습니다 .
이와 같은 도우미를 작성할 때 쉼표 연산자가 가장 유용하다는 것을 알았습니다.
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
쉼표를 || 또는 &&,하지만 함수가 무엇을 반환하는지 알아야합니다.
그보다 더 중요한 것은 쉼표 구분자가 의도를 전달한다는 것입니다 . 코드 는 왼쪽 피연산자가 무엇을 평가하는지 신경 쓰지 않는 반면, 대안은 거기에있는 또 다른 이유가있을 수 있습니다. 이것은 차례로 이해하고 리팩토링하는 것을 더 쉽게 만듭니다. 함수 반환 유형이 변경되는 경우 위 코드는 영향을받지 않습니다.
당연히 다른 방법으로도 같은 것을 달성 할 수 있지만 간결하지는 않습니다. 만약 || &&는 공통적으로 사용되는 장소를 찾았으므로 쉼표 연산자도 마찬가지입니다.
tap
( ramdajs.com/docs/#tap ). 기본적으로 부작용을 실행 한 다음 초기 값을 반환합니다. 함수형 프로그래밍에 매우 유용합니다. :)
내가 사용하는 전형적인 경우는 선택적 인수 구문 분석 중입니다. 인수 구문 분석이 함수 본문을 지배하지 않도록 더 읽기 쉽고 간결하게 만듭니다.
/**
* @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();
// ...
}
배열이 있다고 가정 해 보겠습니다.
arr = [];
push
해당 배열에 있을 때 push
의 반환 값, 즉 배열의 새 길이에 거의 관심이 없지만 배열 자체에는 관심이 없습니다 .
arr.push('foo') // ['foo'] seems more interesting than 1
쉼표 연산자를 사용하여 배열에 푸시하고 배열을 쉼표에 대한 마지막 피연산자로 지정한 다음 결과 (배열 자체)를 후속 배열 메서드 호출, 일종의 연결에 사용할 수 있습니다.
(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]
쉼표 연산자를 사용할 수있는 또 다른 영역은 Code Obfuscation 입니다.
개발자가 다음과 같은 코드를 작성한다고 가정 해 보겠습니다.
var foo = 'bar';
이제 그녀는 코드를 난독 화하기로 결정합니다. 사용 된 도구는 다음과 같이 코드를 변경할 수 있습니다.
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
var i, j, k;
대var i; var j, var k
?