조건문을 단축하는 방법


154

다음과 같은 매우 긴 조건문이 있습니다.

if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
    // do something.
}

이 표현 / 문을보다 간결한 형태로 리팩터링 할 수 있는지 궁금합니다.

이것을 달성하는 방법에 대한 아이디어가 있습니까?


23
배열에 넣고 사용할 수 in있습니까?
jeremy


누군가가 가장 빠른 것을 확인할 수있는 경우에만
Muhammad Umer

3
이것은 아마 모든 사람에게 충격이지만 OP가 가지고있는 것은 속도에서 확실한 승자입니다 !!!!!!! 브라우저가 이것을 많이 최적화했을 수도 있습니다. 결과 : (1) if ||. (2) switch진술. (3) 정규식. (4) ~. jsperf.com/if-statements-test-techsin
Muhammad Umer

3
또한 잘못된 방향으로 접근하고있을 수 있습니다. 이 경우 4 가지 유형에 공통점이 있습니다. 무엇입니까? 좀 더 극단적 인 경우에이 조건에 맞게 10 가지 유형을 추가해야한다면 어떨까요? 아니면 100? 더 많은 것이 있다면 아마도이 솔루션 또는 다른 제안 된 솔루션을 사용하지 않을 것입니다. 이와 같은 큰 if 문을보고 코드 냄새라고 생각하면 좋은 징조입니다. 이것을 더 간결하게 만드는 가장 좋은 방법은 if ​​(test.your_common_condition)를 쓸 수있는 것입니다. 이러한 맥락에서 이해하는 것이 더 쉽고 더 확장 가능합니다.
gmacdougall

답변:


241

값을 배열에 넣고 항목이 배열에 있는지 확인하십시오.

if ([1, 2, 3, 4].includes(test.type)) {
    // Do something
}

지원하는 브라우저에 Array#includes방법 이없는 경우이 polyfill을 사용할 수 있습니다 .


~물결표 바로 가기에 대한 간단한 설명 :

업데이트 : 이제 includes방법 이 있으므로 ~더 이상 해킹 을 사용할 필요가 없습니다. 작동 방식을 알고 있거나 다른 코드에서 문제를 겪고있는 사람들을 위해 여기에 보관하십시오.

indexOfis 의 결과를 확인하는 대신 >= 0멋진 지름길이 있습니다.

if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
    // Do something
}

여기 바이올린이 있습니다 : http://jsfiddle.net/HYJvK/

이것은 어떻게 작동합니까? 배열에서 항목을 찾으면 indexOf해당 색인을 리턴합니다. 항목을 찾지 못하면를 반환 -1합니다. 너무 많은 세부 사항에 들어가기없이,이 ~A는 비트 NOT 연산자 반환합니다 0에만 -1.

~반환 값을 비교하는 것보다 간결하기 때문에 바로 가기를 사용하는 것이 좋습니다. JavaScript in_array에 부울을 직접 반환 하는 함수 (PHP와 유사)를 갖기를 바랍니다 .하지만 그것은 단지 희망적 인 생각입니다 ( 업데이트 : 이제 수행합니다 includes. 위 참조). jQuery 's inArray는 PHP의 메소드 시그니처를 공유하면서 실제로 기본 indexOf기능을 모방합니다 (인덱스가 진정으로 뒤 따르면 다른 경우에 유용함).

중요 사항 : 물결표 바로 가기를 사용하여 몇 가지가 같은 논쟁에 감싸여있는 것 같다 격렬 코드가 분명한만큼이 아닌 모든 비용 (이 답변에 의견을 참조)에서 피해야한다고 생각합니다. 그들의 감정을 공유한다면 .indexOf(...) >= 0해결책을 고수해야합니다 .


조금 더 설명 :

JavaScript의 정수는 부호가 있습니다. 이는 가장 왼쪽 비트가 부호 비트로 예약됨을 의미합니다. 숫자가 양수인지 음수인지를 나타내는 플래그 1.

32 비트 이진 형식의 샘플 양수는 다음과 같습니다.

1 :    00000000000000000000000000000001
2 :    00000000000000000000000000000010
3 :    00000000000000000000000000000011
15:    00000000000000000000000000001111

이제 같은 숫자이지만 음수입니다.

-1 :   11111111111111111111111111111111
-2 :   11111111111111111111111111111110
-3 :   11111111111111111111111111111101
-15:   11111111111111111111111111110001

음수에 왜 이렇게 이상한 조합이 있습니까? 단순한. 음수는 단순히 양수 + 1의 역수입니다. 양수에 음수를 추가하면 항상 항복해야합니다 0.

이것을 이해하기 위해 간단한 이진 산술을 해 봅시다.

여기에 우리가 추가 할 어떻게 -1+1:

   00000000000000000000000000000001      +1
+  11111111111111111111111111111111      -1
-------------------------------------------
=  00000000000000000000000000000000       0

그리고 여기에 우리가 추가 할 어떻게 -15+15:

   00000000000000000000000000001111      +15
+  11111111111111111111111111110001      -15
--------------------------------------------
=  00000000000000000000000000000000        0

결과를 어떻게 얻습니까? 우리가 학교에서 배운 방식을 정기적으로 추가함으로써 가장 오른쪽 열에서 시작하여 모든 행을 더합니다. 합계가 가장 큰 한 자리 수보다 큰 경우 (10 진수는 9이지만 2 진수는 1) 나머지는 다음 열로 넘어갑니다.

이제 알 수 있듯이, 양수에 음수를 추가하면 모든 0s 가 아닌 맨 오른쪽 열에 는 항상 2가 있으며 1함께 추가하면 2. 두 존재의 이진 표현은 10, 우리가 가지고 1다음 열로하고를 넣어 0첫 번째 열의 결과를. 왼쪽에있는 다른 모든 열에는가있는 행이 하나뿐 1이므로 1이전 열에서 이월 된 값이 다시 합산됩니다 2.이 과정은 맨 왼쪽 열에 도달 할 때까지 반복됩니다. 은 1이월이 넘쳐 분실, 그래서 아무데도 갈해야하고, 우리는 남아있는 수 0에 걸쳐 전부입니다.

이 시스템을 2의 보수 라고 합니다. 이에 대한 자세한 내용은 여기를 참조하십시오.

부호있는 정수에 대한 2의 보완 표현 .


이제 2의 보수 과정의 충돌 과정이 끝났 -1으므로 이진 표현이 1전체에 걸쳐 있는 유일한 숫자 임을 알 수 있습니다.

~비트 NOT 연산자를 사용하면 주어진 숫자의 모든 비트가 반전됩니다. 0모든 비트를 반전시키는 것으로부터 돌아 오는 유일한 방법 은 우리가 모두 시작하는 것입니다 1.

따라서이 모든 것은 is 인 경우 ~n에만 반환 된다는 긴 바람의 표현이었습니다 .0n-1


59
비트 연산자를 사용하는 것이 섹시하지만 실제로 !== -1생각할 수있는 방법 보다 더 좋 습니까? 명시 적 부울 논리가 0의 거짓을 암시 적으로 사용하는 것보다 더 적절하지 않습니까?
Phil

21
근사한 기술이지만 마음에 들지 않습니다. 코드가 무엇을하고 있는지 한눈에 알 수 없으므로 유지할 수 없습니다. 나는 "Yuriy Galanter"의 대답을 선호합니다.
Jon Rea

65
-1 명의 새로운 프로그래머는 이와 같은 답변을보고, 그것이 시원하고 수용 가능한 코딩 방법이라고 생각하고 5 년 안에 코드를 유지하고 머리를 찢어 야합니다
BlueRaja-Danny Pflughoeft

23
이 관용구는 내 전문 분야 인 C #, Java 또는 Python과 같은 언어에서는 일반적으로 일반적이지 않습니다. 방금 현지 자바 스크립트 전문가 몇 명에게 물어 봤는데 그 어느 누구도 이전에 본 적이 없었습니다. 주장하는 것만 큼 흔하지는 않습니다. 그것은 훨씬 더 명확하고 일반적인 것을 위해 항상 피해야한다 != -1.
BlueRaja-대니 Pflughoeft

12
-1 비트 표현에 대해 실제로 많은 것을 지정하지 않는 언어에서 불필요한 비트 피딩으로 인해 -1입니다. 또한이 답변의 대부분은 bitfiddling을 설명합니다. 해킹을 설명하기 위해 20 개의 문단을 작성해야한다면 시간이 정말 절약됩니까?
푹신한

242

fall thru를 통해 switch 문을 사용할 수 있습니다.

switch (test.type) {

  case "itema":
  case "itemb":
  case "itemc":
  case "itemd":
    // do something
}

9
배열 방식의 인덱스는 기본적으로 if와 동일합니다.
NimChimpsky

6
@ kojiro 슬프게도 정답은 이것입니다. 그러나 멋진 배열 배열 대신 이것에주의를 기울일 수는 없습니다.
Manu343726

1
나는이 대답이 여기에 있어야한다는 것을 알았지 만 그것을 찾으려면 아래쪽으로 스크롤해야했습니다. switch 문은 정확히 다른 언어로 설계되고 다른 언어로 이어집니다. 나는 많은 사람들이 switch statement에서 'fall through'방법에 대해 모른다는 것을 발견했다.
Jimmy Johnson

3
이 솔루션은 Firefox 및 Safari에서 가장 빠르며 ||Chrome 에서 두 번째로 빠릅니다 (원본 다음 ). jsperf.com/if-statements-test-techsin
pabouk

3
많은 조건이있는 경우 메소드로 작성하는 것이 끔찍하다고 생각합니다 ... 몇 가지 조건에서는 괜찮지 만 10 이상에서는 배열이 코드를 깔끔하게 유지하려고합니다.
yu_ominae

63

과학 사용 : idfah가 말한 것과 가장 빠른 속도를 위해 코드를 짧게 유지 하면서이 작업을 수행해야합니다.

~방법보다 빠릅니다

var x = test.type;
if (x == 'itema' ||
    x == 'itemb' ||
    x == 'itemc' ||
    x == 'itemd') {
    //do something
}

http://jsperf.com/if-statements-test-techsin 여기에 이미지 설명을 입력하십시오 (상단 세트 : Chrome, 하단 세트 : Firefox)

결론 :

경우 가능성은 당신은 어떤 사람이 당신이 최대의 성능을 얻을 수보다 발생할 가능성이 알고 if ||, switch fall through하고 if(obj[keyval]).

경우 가능성이 많은 , 그 중 사람이 가장 즉, 하나의 발생, 하나는 가장 가능성이 당신이 객체 조회에서 대부분의 성능을보다가 발생하는 것을 알 수있을 수 if(obj[keyval])regex이 맞는 경우입니다.

http://jsperf.com/if-statements-test-techsin/12

새로운 것이 나오면 업데이트하겠습니다.


2
정말 좋은 게시물 +1! 올바르게 이해 switch case하면 가장 빠른 방법입니까?
user1477388

1
파이어 폭스 예, 크롬에서if ( ...||...||...)...
무하마드 우 메르

8
이 입력에 대해 많은 루프를 실제로 수행하면 더 빠르지 만 n이 큰 루프 ( "itemX"문자열 수)가 하나 인 루프는 훨씬 느립니다. 나는 이 코드 생성기 를 해킹 하여 검증하거나 반박하는 데 사용할 수 있습니다. obj["itemX"]n이 크면 매우 빠릅니다. 기본적으로 빠른 것은 상황에 따라 다릅니다. 즐기세요
kojiro

3
가장 빠른 방법이지만 중요 합니까?
congusbongus

1
@Mich 속도를 위해서 코드의 우아함을 희생하지 마십시오. 이것은 많은 사람들이 당신에게 말할 것입니다. 결국 상식을 사용하십시오.
Andre Figueiredo

32

문자열과 비교할 때 패턴이있는 경우 정규식 사용을 고려하십시오.

그렇지 않으면 코드를 줄이려고하면 코드가 난독해질 것입니다. 단순히 줄을 감싸서 예쁘게 만드는 것을 고려하십시오.

if (test.type == 'itema' ||
    test.type == 'itemb' ||
    test.type == 'itemc' ||
    test.type == 'itemd') {
    do something.
}


1
또한 프로젝트가 유지 보수 모드로 전환 될 때 가장 쉽게 확장 할 수 있습니다 (예 : 등 (test.type == 'itemf' && foo.mode == 'detailed'))
Izkata

16
var possibilities = {
  "itema": 1,
  "itemb": 1,
  "itemc": 1,
…};
if (test.type in possibilities) {  }

객체를 연관 배열로 사용하는 것이 일반적이지만 JavaScript에는 기본 세트가 없으므로 저렴한 세트로도 객체를 사용할 수 있습니다.


FlyingCat가 단축하려고하는 일반적인 if 문보다 얼마나 짧습니까?
dcarson

1
if모든 공백을 제거하면 @dcarson OP의 조건문에 78자가 걸립니다. 다음과 같이 쓰면 54이 걸립니다 test.type in {"itema":1,"itemb":1,"itemc":1,"itemd":1}. 기본적으로 그의 추가 키마다 두 개의 광산을 사용할 때마다 4자를 사용합니다.
kojiro

1
그러나 당신은 할 수 있습니다 : if (possibilities [test.type]) 그리고 전체 2 문자를 저장하십시오! :)
dc5

15
if( /^item[a-d]$/.test(test.type) ) { /* do something */ }

또는 품목이 균일하지 않은 경우 :

if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }

9
"어떤 사람들은 문제에 직면했을 때 '나는 정규 표현식을 사용할 것입니다'라고 생각합니다. 이제 두 가지 문제가 있습니다. " -1997 년 Jamie Zawinski
Moshe Katz

5
@MosheKatz 사람들이 그 인용문에 대해 반박하고 싶어한다는 것을 이해할 수 있지만 사람들은 확실히 부적합한 것들에 대해 정규 표현식을 사용하지만 이것은 그중 하나가 아닙니다. OP가 제공하는 경우 이는 기준과 일치 할뿐만 아니라 매우 잘 수행됩니다. 정규 표현식은 본질적으로 악하지 않으며, 잘 정의 된 매개 변수를 사용하여 문자열을 일치시키는 것이 목적입니다.
Thor84no

3
@ Thor84no 일반적으로, 질문자는 실제로 첫 번째 사례와 같은 고안된 예와 일치하지 않으려 고 시도하고 실제 일치는 그렇게 간단하지 않다고 가정합니다.이 경우 RegEx가 진행되지 않는다고 생각합니다 올바른 방법으로 다시 말해, RegEx가 파이프 문자로 구분 된 옵션 목록 인 경우 다른 제안보다 더 읽기 어렵고 효율성이 떨어질 수 있습니다.
Moshe Katz

10

훌륭한 답변이지만 코드 중 하나를 함수로 래핑하여 코드를 훨씬 더 읽기 쉽게 만들 수 있습니다.

이것은 복잡한 if 문입니다. 여러분이나 다른 사람이 몇 년 안에 코드를 읽을 때, 무슨 일이 일어나고 있는지 이해하기 위해 섹션을 찾기 위해 스캔 할 것입니다. 이 수준의 비즈니스 로직이 포함 된 진술은 테스트 대상을 해결하는 동안 몇 초 동안 걸려 넘어 질 수 있습니다. 이와 같은 코드로 스캔을 계속할 수 있습니다.

if(CheckIfBusinessRuleIsTrue())
{
    //Do Something
}

function CheckIfBusinessRuleIsTrue() 
{
    return (the best solution from previous posts here);
}

함수의 이름을 명시 적으로 지정하면 테스트 대상을 즉시 알 수 있으며 코드를 훨씬 쉽게 스캔하고 이해할 수 있습니다.


1
내가 본 최고의 답변. 실제로 저는 사람들이 좋은 디자인의 원칙에 관심이 없다는 것을 알고 있습니다. 시스템을 나중에 유지 관리 할 수 ​​있도록 무언가를 빠르게 수정하고 코드를 개선하는 것을 잊어 버리십시오!
Maykonn

어떻 // CheckIfBusinessRuleIsTrue습니까?
daniel1426

4

모든 답변을 Javascript Set 에 넣은 다음 Set 을 호출 .contains()하면됩니다.

여전히 모든 내용을 선언해야하지만 인라인 호출은 더 짧습니다.

다음과 같은 것 :

var itemSet = new Set(["itema","itemb","itemc","itemd"]);
if( itemSet.contains( test.type ){}

4
이는 OP가하려는 일을 달성하기위한 엄청나게 낭비적인 방법 인 것 같습니다. 당신이 동안 그래서 수있는 별도의 제 3 자 라이브러리를 포함, 객체를 인스턴스화하고 통화 그것에 방법, 당신은 아마 안된다.
KaptajnKold

@Captain Cold : OP는 메모리 풋 프린트가 아닌 간결성을 요구했습니다. 다른 작업에 세트를 재사용 할 수 있습니까?
귀도 안 셀미

1
물론 이죠,하지만 그렇다고하더라도 : 모든 정직에서와 당신은 이제까지 이 직접합니까? 내가 이것을 야생에서 본 적이 있다면, 그것을 주요 WTF라고 생각할 것이다.
KaptajnKold

1
네, 그렇습니다 (+1을주었습니다). 그러나이 검사는 다른 곳에서는 수행되지 않는다고 가정합니다. 다른 곳에서 시험 및 / 또는 시험 변경을하는 경우, 세트 사용이 의미가있을 수 있습니다. 최상의 솔루션을 선택하기 위해 OP에 맡깁니다. 이것이 독방 적 인 사용법이라면 Set을 사용하면 As Clown 모자가 부끄러워 할 것이라고 동의합니다.
귀도 안 셀미

2
실제로 선택한 답변이 절대적으로 끔찍하고 더 읽기가 불가능하기 때문에 Set을 사용하는 것이 더 낫다고 생각합니다.
귀도 안 셀미

2

이것을 달성하는 가장 좋아하는 방법 중 하나는 underscore.js와 같은 라이브러리를 사용하는 것입니다.

var isItem = _.some(['itema','itemb','itemc','itemd'], function(item) {
    return test.type === item;
});

if(isItem) {
    // One of them was true
}

http://underscorejs.org/#some


1
containssome
Dennis

1
이를 위해 라이브러리를 사용할 필요가 없습니다 : someEC5의 Array 프로토 타입에 대한 함수입니다.
KaptajnKold

2
물론 모든 사람이 EC5를 지원할 수있는 것은 아닙니다. 게다가, 나는 단지 밑줄을 정말로 좋아합니다. :)
jcreamer898 13:21

경우 당신이 이미 밑줄 같은 라이브러리를 사용, 이것은 아마도 가장 쉬운 방법입니다. 그렇지 않으면 하나의 함수에 대해서만 전체 라이브러리를로드하는 것이 의미가 없습니다.
Moshe Katz

2

내가 찾은 또 다른 멋진 방법은 이것입니다 ...

if ('a' in oc(['a','b','c'])) { //dosomething }

function oc(a)
{
  var o = {};
  for(var i=0;i<a.length;i++)  o[a[i]]='';
  return o;
}

물론 당신이 볼 수 있듯이 이것은 한 단계 더 나아가고 논리를 쉽게 따를 수있게합니다.

http://snook.ca/archives/javascript/testing_for_a_v

~ && ||와 같은 연산자 사용 ((), ()) ~~는 나중에 코드가 깨질 때만 좋습니다. 어디서부터 시작해야할지 모르겠습니다. 따라서 가독성은 BIG입니다.

당신이 그것을 더 짧게 만들 수 있다면.

('a' in oc(['a','b','c'])) && statement;
('a' in oc(['a','b','c'])) && (statements,statements);
('a' in oc(['a','b','c']))?statement:elseStatement;
('a' in oc(['a','b','c']))?(statements,statements):(elseStatements,elseStatements);

당신이 역으로하고 싶다면

('a' in oc(['a','b','c'])) || statement;

2

그냥 사용하는 switch대신 문을 if문 :

switch (test.type) {

  case "itema":case "itemb":case "itemc":case "itemd":
    // do your process
  case "other cases":...:
    // do other processes
  default:
    // do processes when test.type does not meet your predictions.
}

Switch 또한 많은 조건을 비교하는 것보다 빠르게 작동합니다. if


2

매우 긴 문자열 목록의 경우이 아이디어는 몇 가지 문자를 절약합니다 (실제로 권장하지는 않지만 작동해야 함).

test.type에서 발생하지 않는 문자를 선택하고 구분 기호로 사용하여 하나의 긴 문자열에 붙여 넣고 다음을 검색하십시오.

if ("/itema/itemb/itemc/itemd/".indexOf("/"+test.type+"/")>=0) {
  // doSomething
}

문자열이 더 제한되는 경우 구분 기호를 생략 할 수도 있습니다.

if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
  // doSomething
}

...이 경우에는 오 탐지에주의해야합니다 (예 : "embite"는 해당 버전에서 일치 함)


2

가독성을 위해 테스트를위한 함수를 작성하십시오 (예, 한 줄 함수).

function isTypeDefined(test) {
    return test.type == 'itema' ||
           test.type == 'itemb' ||
           test.type == 'itemc' ||
           test.type == 'itemd';
}

그런 다음 호출하십시오.


    if (isTypeDefined(test)) {

}
...

1

이런 종류의 if 조건을 작성할 때 두 가지 목표가 있다고 생각합니다.

  1. 짧음
  2. 가독성

때때로 # 1이 가장 빠를 수도 있지만 나중에 쉽게 유지 보수하기 위해 # 2를 사용합니다. 시나리오에 따라 나는 종종 Walter의 답변을 변형하여 선택합니다.

시작하려면 기존 라이브러리의 일부로 전 세계적으로 사용 가능한 기능이 있습니다.

function isDefined(obj){
  return (typeof(obj) != 'undefined');
}

그런 다음 실제로 당신과 비슷한 if 조건을 실행하고 싶을 때 유효한 값 목록으로 객체를 만듭니다.

var validOptions = {
  "itema":1,
  "itemb":1,
  "itemc":1,
  "itemd":1
};
if(isDefined(validOptions[test.type])){
  //do something...
}

switch / case 문만큼 빠르지 않고 다른 예제보다 조금 더 장황하지만 코드의 다른 곳에서 객체를 재사용하는 것이 종종 편리합니다.

위에서 만든 jsperf 샘플 중 하나를 피기 백하여이 테스트와 속도를 비교하는 변형을 추가했습니다. http://jsperf.com/if-statements-test-techsin/6 내가 주목 한 가장 흥미로운 점은 Firefox의 특정 테스트 콤보가 Chrome보다 훨씬 빠르다는 것입니다.


1

간단한 for 루프로 해결할 수 있습니다.

test = {};
test.type = 'itema';

for(var i=['itema','itemb','itemc']; i[0]==test.type && [
    (function() {
        // do something
        console.log('matched!');
    })()
]; i.shift());

for 루프의 첫 번째 섹션을 사용하여 일치시킬 인수를 초기화하고 두 번째 섹션은 for 루프 실행을 중지하고 세 번째 섹션을 사용하여 루프를 종료합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.