암묵적 타입캐스팅 피하기


자바스크립트는 변수를 비교할 때 암묵적으로 타입캐스팅을 실행한다. 때문에 false == 0 이나 "" == 0과 같은 비교가 true를 반환한다.

암묵적 타입캐스팅으로 인한 혼동을 막기 위해서는 항상 표현식과 값과 타입을 모두 확인하는 ===와 !== 연산자를 사용해야 한다.

var zero = 0;
if(zero === false){
// zero는 0이고 false가 아니기 때문에 이 블록은 실행되지 않는다.
console.log("oen : " + zero);
}

// 안티패턴
if(zero == false){
// 이 블록은 실행된다.
console.log("two : " + zero);
}


switch 패턴

다음 패턴을 따르면 switch문의 가독성과 견고성을 향상시킬 수 있다.

var inspect_me = 0,
result = '';

switch(inspect_me){
case 0:
result = "zero";
break;
case 1:
result = "oen";
break;
default:
result = "unknown";
}

console.log(result);


위의 간단한 예제에서 지켜진 규칙은 다음과 같다.

  • 각 case문을 switch문에 맞추어 정렬한다.(일반적인 중괄호 내 들여쓰기 규칙에서 벗어나는 방식이다)
  • 각 case문 안에서 코드를 들여쓰기 한다.
  • 각 case문은 명확하게 break;로 종료한다.
  • break문을 생략하여 통과(fail-through) 시키지 않는다. 그런 방법이 최선책이라는 확신이 있다면 해당 case에 반드시 기록을 남긴다.
  • 상응하는 case문이 하나도 없을때도 정상적인 결과가 나올 수 있도록 switch문 마지막에는 default:문을 쓴다.


for-in 루프

for-in 루프는 배열이 아닌 객체를 순회할 때만 사용해야 한다. for-in 으로 루프를 도는것을 열거 라고도 한다.


// 객체
var man = {
hands: 2,
legs: 2,
heads: 1
};

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


이 예제에서는 객체 리터럴을 사용하여 man 이라는 이름의 간단한 객체를 정의했다. man을 정의하기 전이나 후 어디선가 Object 프로토타입에 clone()이라는 이름의 메서드가 편의상 추가 되었다.


man을 열거할때 hasOwnProperty()를 호출하여 걸러내지 않으면 clone()이 나오게 되므로 동작방식이 바람직 하지 않다.


// 객체
var man = {
hands: 2,
legs: 2,
heads: 1
};

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

//1.
// for-in 루프
for(var i in man){
if(man.hasOwnProperty(i)){ // 프로토타입 프로퍼티를 걸러낸다.
console.log(i + " : " + man[i]);
}
}

/*
콘솔에 출력되는 결과
hands : 2
legs : 2
heads : 1
*/

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

/*
콘솔에 출력되는 결과
hands : 2
legs : 2
heads : 1
clone : function(){}
*/


Object.property에서 hasOwnProperty()를 호출하는 것도 하나의 패턴이다.


for (i in man){
if(Object.prototype.hasOwnProperty.call(man, i)){ // 걸러내기
console.log(i + " : " + man[i])
}
}


이 방법은 man 객체가 hasOwnProperty를 재정의하여 덮어썼을 경우에도 활용 할 수 있다는 장점이 있다. 프로퍼티 탐색이 Object까지 거슬러 올라가지 않게 하려면 지역변수를 사용하여 이 메서드를 캐시하면된다.


var i,
hasOwn = Object.prototype.hasOwnProperty;
for(i in man){
if (hasOwn.call(man, i)){ // 걸러내기
console.log(i + " : " + man[i]);
}
}


for 루프

 

최적화 되지 않은 루프

이 패턴의 문제점은 루프 순회시 마다 배열의 length에 접근한다는 점이다.


for(var i=0; i<myarray.length; i++){ 
	// myarray[i] 를 다루는 코드 
}

 

for 루프를 좀더 최적화 하기 위해서는 다음 예제처럼 배열의 length를 캐시해야 한다.


for(var i=0, max = myarray.length; i<max; i++){
	// myarray[i] 를 다루는 코드
}

이렇게 하면 length 값을 한번만 구하고 루프를 도는 동안 이 값을 사용하게 된다.

 

단일 var 패턴을 따르자면, var 문을 루프 외부로 빼내어 다음과 같이 만들수 있다.


function looper() { 
	var i=0, max myarray = []; 
    // ... 
    for(i=0, max = myarray.length; i<max; i++){
    // myarray[i] 를 다루는 코드
    } 
}

이 패턴은 단일 var 패턴을 고수하여 일관성을지킨다는 장점이 있다.

 

i++ 명령문을 다음중 하나로 대체할 수 있으며, JSLint는 이 방법을 권장한다.

i = i+1

i += 1

 

for 문에는 두 가지 변형 패턴이 있다.

이 패턴들은 다음과 같은 미세 최적화를 시도 한다.

 

첫번째 변형 패턴


var i, myarray = [];

for (i = myarray.length; i--){ 
	// myarray[i]를 다루는 코드 
}

두번째 변형 패턴은 whlie 루프를 사용한다.


var myarray = [],i = myarray.length;
    
while (i--){
	// myarray[i] 를 다루는 코드
}

    + Recent posts