development

조건문을 단축하는 방법

big-blog 2020. 6. 8. 07:57
반응형

조건문을 단축하는 방법


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

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

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

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


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

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


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

switch (test.type) {

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

과학 사용 : 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

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


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

Otherwise, I suspect attempting to shorten it will just obfuscate your code. Consider simply wrapping the lines to make it pretty.

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

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

Using an object as an associative array is a pretty common thing, but since JavaScript doesn't have a native set you can use objects as cheap sets as well.


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

or if the items are not that uniform, then:

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

Excellent answers, but you could make the code far more readable by wrapping one of them in a function.

This is complex if statement, when you (or someone else) read the code in a years time, you will be scanning through to find the section to understand what is happening. A statement with this level of business logic will cause you to stumble for a few seconds at while you work out what you are testing. Where as code like this, will allow you to continue scanning.

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

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

Name your function explicitly so it immediately obvious what you are testing and your code will be much easier to scan and understand.


You could put all the answers into a Javascript Set and then just call .contains() on the set.

You still have to declare all the contents, but the inline call will be shorter.

Something like:

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

One of my favorite ways of accomplishing this is with a library such as 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


another way or another awesome way i found is this...

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;
}

of course as you can see this takes things one step further and make them easy follow logic.

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

using operators such as ~ && || ((),()) ~~ is fine only if your code breaks later on. You won't know where to start. So readability is BIG.

if you must you could make it shorter.

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

and if you want to do inverse

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

Just use a switch statement instead of if statement:

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 also works faster than comparing lots of conditionals within an if


For very long lists of strings, this idea would save a few characters (not saying I'd recommend it in real life, but it should work).

Choose a character that you know won't occur in your test.type, use it as a delimiter, stick them all into one long string and search that:

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

If your strings happen to be further constrained, you could even omit the delimiters...

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

...but you'd have to be careful of false positives in that case (e.g. "embite" would match in that version)


For readability create a function for the test (yes, a one line function):

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

then call it:


    if (isTypeDefined(test)) {
}
...

I think there are 2 objectives when writing this kind of if condition.

  1. brevity
  2. readability

As such sometimes #1 might be the fastest, but I'll take #2 for easy maintenance later on. Depending on the scenario I will often opt for a variation of Walter's answer.

To start I have a globally available function as part of my existing library.

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

and then when I actually want to run an if condition similar to yours I'd create an object with a list of the valid values:

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

It isn't as quick as a switch/case statement and a bit more verbose than some of the other examples but I often get re-use of the object elsewhere in the code which can be quite handy.

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


간단한 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 루프 실행을 중지하고 세 번째 섹션을 사용하여 루프를 종료합니다.

참고 URL : https://stackoverflow.com/questions/18347033/how-to-shorten-my-conditional-statements

반응형