티스토리 뷰

728x90
반응형

반복문과 조건문 올바른 사용법 및 최적화

프로그래밍 언어 대부분이 코드 실행 시간의 상당 부분을 루프에서 소비한다.
무한 루프나 오래 지속되는 루프는 일반적으로 사용자가 사용할때 심한 악영향을 끼친다. 
주의 요망~

for문

-js에서 가장 많이 쓰이는 루프 구조
 
 
for( 초기화; 실행조건; 실행후코드){
  //루프 몸체
}
 
 
초기화, 실행조건, 실행후 코드, 루프 몸체 4개의 부분으로 구성됩니다.
 

초기화-> 실행조건->루프 몸체->실행후 코드

          -> 실행조건->루프 몸체->실행후 코드

 
         
 tip 

초기화( for( var i=0 으로 지정하는 구문 뜻함 )는 최초 한번만 일어난다.
for문의 초기화 부분에서 var로 선언한 변수의 스코프는 루프레벨이 아니라 함수 레벨.  
즉 함수레벨의 스코프 밖에 없으므로 for문안에서 변수를 선언하든 바깥에서 선언하든 마찬가지이다.
         

while문

 - 실행 조건과 루프 몸체만으로 구성되는 검사후 루프
 var i=0;
 while(i<10){
     //루프몸체
     i++;
 }
 
 
루프 몸체를 실행하기 전에 실행 조건을 검사.
실행조건이 true로 평가되면 루프 몸체를 실행하고 실행 조건이 false로 평가되면 루프 몸체를 실행X.
모든 for문을 while문으로 바꿔 쓸 수 있고 반대로도 가능.
         
 

do-while문 

do-while문은 자바스크립트에서 유일한 검사전 루프이며  
do - while 문의 루프 몸체는 최소한 한번은 반드시 실행된다. 
실행후 조건을 평가해서 루프 몸체를 다시 실행할지 결정. 루프 몸체,  실행후 조건의 2부분으로 구성.          
 var i=0;
 do{
    //루프 몸체
 }while( i++<10 );
 
 for-in 문 이 루프의 목적은 아주 특수해서 객체의 명명된 속성을 열거할때 씀.
 
 for( var prop in object ){
      //루프 몸체
 }
 
루프를 실행할 때마다 prop변수에 객체 속성의 이름(문자열)이 채워지면 객체에 있는 모든 속성을 반환할때까지 반복.
이 루프는 객체 인스턴스에 있는 속성과 프로토타입 체인을 통해 상속받는 속성을 구분하지 않고 모두 반환.
         
자바스크립트의 네 가지 루프중 명확한 속도 차이가 있는 것은 for-in문 뿐이다. 
for-in문은 루프를 반복할때마다 인스턴스 또는 프로토타입 체인을 검색해야 하므로 상당한 부담이 있고 다른 루프보다 느리다.
 
똑같은 횟수만큼 반복한다고 할때 for-in문은 다른 루프보다 최대 7배까지 느림.
따라서 속성이 몇개인지 알 수 없는 객체에 대해 루프를 실행하고자 하는 것이 아니라면  for-in루프는 안쓰는게 좋음.
 
 
 
 
 
        
결론: 자료 javascript pattern 서적==============================================
 
배열에는 일반적인 for루프를 사용하고 객체에만 for-in루프를 사용하는 것이 바람직하다.
객체의 프로퍼티를 순회할 때는 프로토타입 체인을 따라 상속되는 프로퍼티들을 걸러내기 위해 
hasOwnProperty()메서드를 사용해야 한다.
 
 var man={
      hands:2,
      legs:2,
      heads:1
 }

 //코드 어딘가에서 모든 객체에 메서드 하나가 추가 되었다.
  if( typeof Object.prototype.clone==="undefined"){
      Object.prototype.clone=function(){ };
  }


  //안티패턴-오류를 많이 범할 수 있는 잘못된 패턴
  for( var i in man ){
      if( man.hasOwnProperty(i) ){ //프로토타입 프로퍼티를 걸러낸다.
             console.log( i, ":", man[i] );
      }
  }
  //콘솔 결과
  //hands: 2
  //legs : 2
  //heads : 1

  //안티패턴
  //hasOwnProperty()를 확인하지 않는 for-in 루프
  for( var i in man ){
     console.log( i, ":" +man[i] );
  }

  // 콘솔 결과
  //hands: 2
  //legs : 2
  //heads : 1
  //clone: function()

  //Object.prototype에서 hasOwnProperty()를 호출하는 것도 또 하나의 패턴이다.
  for( var i in man ){
        if( Object.prototype.hasOwnProperty.call( man, i ) ){ //걸러내기
              console.log( i, ":", man[i] );   
        }
  }
 
프로퍼티 탐색이 Object까지 멀리 거슬러 올라가지 않게 하려면 지역변수를 사용하여 이 메서드를 캐시.
 
 
  var i,
  hasOwn=Object.prototype.hasOwnProperty;
  for( i in man ){ 
       if( hasOwn.call( man, i ) ){//걸러내기
            console.log( i, "::", man[i] );
       }
  }
 
 
 
==============================================여기까지 javascript pattern
 
   
 for-in문을 제외한 다른 루프의 성능은 모두 동등하고, 성능이외의 다른 필요성을 근거로 루프를 선택.
 
 1. 루프 몸체에서 하는일 줄이기.
 2. 반복횟수
 
  //원래 루프
  for( var i=0; i<items.length; i++){
       process( items[i] );
  }

  var j=0;
  while( j< items.length ){
     process( items[j++] );
  }

  var k=0;
  do{
     process( items[k++] );
  }while( k<items.length );
      
내부에서 일어나는 방식
 
1. 실행 조건에서 속성 한번 검색(items.length)
2. 실행 조건에서 비교 한번(if<items.length );
3. 실행 조건이 true로 평가되는지 확인하기 위해 비교 한번( i<items.length==true )
4. 증가 연산 한번(i++)
5.배열 검색 한번(item[i]);
6. 함수 호출 한번
 
속성 검색을 한 번만 하고 그 값을 지역 변수에 복사해서 실행 조건에 쓰면 루프의 성능 UP.
      
  //속성 참조를 최소화
  for( var i=0, len=items.length; i<len; i++ ){
      process( items[i] );
  }
 //
  var j=0, count=items.length;
  while(j<count){
       process( items[j++] );
  }
  var k=0, num=item.length;
  do{
      process( items[k++] );
  }while( k<num );
 
고쳐 쓴 루프는 실행 전에 배열의 length속성을 한 번만 검색.
이렇게 하면 실행 조건에 지역 변수만 들어가므로 훨씬 빨리 실행.
 
배열의 길이에 따라 다르지만 브라우저 대부분에서 루프의 총 실행 시간을 25% 정도 줄일 수 있다.
( ie 는 50%까지 줄일 수 있음).
 
      
루프의 순서를 거꾸로 해도 성능을 올릴 수 있다.
 for( var i=items.legnth; i--; ){
     process( items[i] );
  }

  var j=items.length;
  while( j-- ){
    process( items[i] );
  }

  var k=items.length-1;
  do{
      process( items[i] );
  }while( k-- );
      
실행조건을 평가할때 단순히 0과 비교한다.
실행조건을 평가할때는 true와 비교하는데, 자바스크립트에서는
0이 아닌 숫자를 자동으로 true로 평가하며 0은 false로 평가한다.
따라서 실행조건을 0과 비교하는 것은 두번 비교를 한번 비교로 줄이는 효과가 있다.
루프 순서를 거꾸로 하면서 속성 검색도 최소화하면 루프 실행 시간이 처음 보다 5~60% 정도 빨라진다.
 
1. 실행조건에서 비교한번 (i==true)
2. 감소 연산자 한번(i--)
3. 배열 검색 한번(item[i]);
4. 함수 호출 한번(process(item[i]) )
 
ECMA-262 5판에서 array객체의 네이티브 메서드 forEach()를 도입.
이 메서드는 배열 항목을 순회하면서 각각에 대해 함수를 실행한다.
실행할 함수를 forEach()메서드에 매개변수로 전달하며 이 함수를 호출할 때 
배열 항목의 값과 배열항목의 인덱스, 배열자체를 매개변수로 전달한다.
 
파이어폭스와 크롬, 사파리는 forEach()문을 직접 지원. 
자바스크립트 라이브러리 대부분은 같은 기능을 하는 메서드를 제공한다.
  items.forEach( function( value, index, array ){
        process( value );
  });

  //YUI 3
  Y.Array.each( items, function( value, index, array ){
        process( value );
  });

  //jQuery
  jQuery.each( items, function( index, value ) {
      process( value );
  }

  //Prototype
  items.each( function( value, index ){
      process( value );
  });
      
함수에 기반을 둔 반복문은 편리하지만 배열 항목 전체에 대해 함수를 호출하기 때문에 루프보다 느리다.
함수 반복문은 루프보다 최대 8배까지 느리므로 실행속도가 중요할때는 적합하지 않다.
 
 
      
조건문 ( if-else, if-else if, switch )- javascript (자바스크립트 성능 최적화 )   
 
 if-else 문을 쓸지 switch문을 쓸지는 테스트할 조건이 몇 개냐에 따라 다르다는 이론이 지배적이다.
테스트할 조건이 많을수록 if-else 문보다는 switch문이 나을 수 있다.어느쪽이 더 읽기 쉬운가 하는 문제.)
조건이 적으면 if-else 문이 읽기 쉽고  조건이 많으면 switch문이 읽기 쉽다.
      
  if( found ){
      //뭔가 한다.
  }else{
      //다른걸 한다.
  }

  switch( found ){
       case true:
            //뭔가한다.
         break;
    default:
        //다른걸한다.
  }
 
두코드가 하는일 은 똑같고 if-else문이 switch문보다 읽기 쉽다는 사람이 많다.  조건수를 늘리면 의견이 바뀔수 있다.
   if( color=="red" ){
      //뭔가한다.
  }else if( color=="blue"){
      //뭔가한다.
  }else if( color=="brown"){
      //뭔가한다.
  }else if( color=="black"){
       //뭔가한다.
  }else {
     //뭔가한다.
  }

  switch( color ){
      case "red":
            //뭔가한다.
         break;
    case "blue":
            //뭔가한다.
         break;
     case "brown":
            //뭔가한다.
         break;
     case "black":
            //뭔가한다.
         break;
      default:
        //다른걸 한다.
  }
  
일반적으로 말해서 if-else문은 두개의 분명한 값 또는 몇 안되는 범위에서 테스트할 때 가장 적합.
분명한 값 세 개 이상을 테스트한다면 switch문이 더 좋다.
 
 
 
암묵적 타입캐스팅 피하기- javascript pattern
 
자바스크립트는 변수를 비교할때 암묵적으로 타입캐스팅을 실행한다.
때문에 false==0 이나 ""==0 과 같은 비교가 true를 반환한다.
혼동을 막기 위해서는 , 항상 표현식의 값과 타입을 모두 확인하는 ===와 !== 연산자를 사용해야 한다.
var zero=0;
if(zero===false){
   //zero는 0이고 false가 아니기 때문에 이 블록은 실행되지 않는다.
}
//안티패턴-오류를 많이 범할 수 있는 잘못된 패턴
if( zero==false ){
  //이 블록은 실행된다.
}
 
 
 
 
=================================================================================================
 
 
 
 if-else 최적화- javascript (자바스크립트 성능 최적화 )   
 
 if-else 문의 최적화 목표는 분기하기 전에 평가해야 하는 조건의 수를 최소한으로 줄이는 것.
 즉, 가장 쉬운 최적화 방법은 가장 많이 쓰이는 조건이 맨 앞에 있도록 한다.
 
  if( 가장 많이 쓰일 조건){
  //
  }else if( 그 다음으로 많이 쓰일 조건){
  //
  }else{
  //
  }
      
if-else문의 조건 평가를 최적화하는 다른 방법은 if-else문을 중첩.
많은 조건이 있는 한 단계의 if-else문은 여러 개의 조건을 평가해야 하기 때문에 느리다.
      
  if(value==0){
      return result0;
  }else if( value==1 ){
      return result1;
  }else if( value==2 ){
      return result2;
  }else if( value==3 ){
      return result3;
  }else if( value==4 ){
      return result4;
  }else if( value==5 ){
      return result5;
  }else if( value==6 ){
      return result6;
  }else if( value==7 ){
      return result7;
  }else if( value==8 ){
      return result8;
  }else if( value==9 ){
      return result9;
  }else{
      return result0;
  }
 
이 코드를 중첩된 if-else문으로 고쳐 써서 평가할 조건의 수를 줄일 수 있다.
  if( value<6 ){

       if( value<3){
            if( value==0 ){
                 return result0;
            }else if( value==1 ){
                 return result1;
            }else {
                 return result2;
            }
      }else{
            if( value==3){
                return result3;
            }else if(value==4){
                return result4;
            }else{
                return result5;
            }
      } //value<3 end

 }else{

     if( value<8 ){
          if( value==6 ){
              return result6;
          }else{
              return result7;
          }
     }else{
          if( value==8 ){
              return result8;
          }else if( value==9 ){
              return result9;
          }else{
              return result0;
          }
     }// value<8 end
 }// value<6 end
 
 
고쳐 쓴 if-else문은 실행할 때마다 조건으 최대 네 번 평가. 
가능한 값을 몇개의 범위로 나누어 검사한 후 
일치하는 부분을 더 파고드는 방식이다.
 
0과 10사이에 고르게 분포한다면 이 코드를 실행하는 걸리는 
시간은 이전의if-else 문보다 약 절반 정도로 줄어든다.  
이 방법은 범위를 여러 개 검사할 때 가장 효과적이다.
( 값 여러개가 아니다. 값을 여러 개 검사한다면 switch문이 더 적합하다. );

 

 

728x90
반응형

'Programming language > javascript' 카테고리의 다른 글

자바스크립트에서의 this란~  (0) 2013.02.06
리터럴과 생성자 사용법~  (0) 2013.02.06
변수 올바른 사용법과 이해  (0) 2013.02.06
모질라 개발자 네트워크  (0) 2013.01.24
base64 - encode / decode  (0) 2013.01.12
댓글