이 글은 CodeSchool 의 Javascript Best Practices 를 듣고, 주요 내용을 정리한 글입니다.
Ternary Conditional (삼항 연산자)
-
다음과 같은 예문이 있다.
var isArthur = true; var weapon; if(isArthur) { weapon = "Excalibur"; } else { weapon = "Longsword"; }
-
삼항연산자를 이용하면 위의 if else 문을 아래와 같이 바꿀수 있다.
var weapon = isArthur ? "Excalibur" : "Longsword";
-
또한 삼항 연산자를 다음과 같은 형태로도 사용이 가능하다.
// 두개 이상의 변수를 이용하여 값을 받는 경우 isArthur && isKing ? (weapon = "Ex", helmet = "Goose") : (weapon = "ln", helmet = "Iron") // 즉시 실행함수로 값을 받는 경우 isArthur && isKing ? function () { // ... }(); : function () { // ... }();
Logical Assignment 1 (OR)
- OR 연산자 : “falsy” 하지 않은 가장 첫번째 마주친 값을 갖는다.
-
아래의 삼항 연산자를 OR 연산자를 이용하여 다음과 같이 줄일 수 있다.
// 삼항연산자 사용 function addSword(sword) { this.swords = this.swords ? this.swords : [ ]; this.swords = push.(sword); } // OR 연산자 사용 function addSword(sword) { this.swords = this.swords || [ ]; this.swords = push.(sword); } // OR 연산자 잘못 사용한 예 function addSword(sword) { this.swords = [ ] || this.swords; this.swords = push.(sword); } // 위의 경우 계속 new array 를 할당함.
-
OR 연산자의 잘못된 사용 예를 더 본다.
// 잘못된 OR 연산자 사용 예 var result1 = 42 || undefined; // undefined 를 절대로 마주치지 않는다. var result2 = ["Sweet", "array"] || 0; // 0을 절대로 마주치지 않는다. var result3 = {type: "ring", stone: "diamond"} || ""; // "" 를 절대로 맞추지지 않는다. // 위를 고쳐보면, var result1 = undefined || 42; var result2 = 0 || ["Sweet", "array"]; // 0을 절대로 마주치지 않는다. var result3 = "" || {type: "ring", stone: "diamond"}; // "" 를 절대로 맞추지지 않는다.
Logical Assignment 2 (And)
- OR 연산자와는 다르게 두개의 “truthy” 값이 있으면, 마지막으로 확인한 truthy 값이 리턴된다.
-
“falsy” 값의 경우에는 OR 연산자와 동일하게 동작한다.
var result1 = "King" && "Arthur"; console.log(result1); //Arthur var result2 = "Arthur" && "King"; console.log(result2); // King
Switch Blocks
-
반복되는
if else
문과switch
문의 차이점은, 순차적으로 모든 if 문을 도느냐. 아니면 해당하는 case 로 바로 가서 불필요한 연산을 줄이느냐의 차이이다.var regimnet = 3; if (regiment == 1) { ... } else if (regiment == 2) { ... } else if (regiment == 3) { // 앞 1,2 를 거쳐 3으로 온다. ... } switch (regiment) { case 1: ... case 2: ... case 3: // 3으로 바로 온다. ... }
-
break 문을 사용하지 않고, 공통된 property 를 상위 case 에서 부터 순차적으로 접근하여 추가하는 방법도 있다.
Loop Optimization
-
컴퓨터 메모리 관점에서 일반적인 for 문의 연산 순서를 보자.
treasureChest = { necklaces: ["A", "B", "C", "D"]; }; for (var i = 0; i < treasureChest.necklaces.length; i++) { console.log(treasureChest.necklaces[i]); }
-
위 for 문에서 메모리 연산이 필요한 부분은 다음과 같다.
- i 값 탐색
- treasureChest 객체 탐색
- necklaces 속성 탐색
- necklaces 속성의 배열 인덱스 탐색
- length 프로퍼티 검색
위의 연산을 최적화 해보자 : Cache the necessary values in the local variables
// 1. length property 를 한번만 접근 (기존 for 문은 반복시 마다 접근)
var x = treasureChest.necklaces.length;
for (var i = 0; i < x; i++) {
console.log(treasureChest.necklaces[i]);
}
- 위의 리팩토링으로 연산 수가 다음과 같이 줄어들었다.
- TBC
-
위 코드는 더 개선할 수 있다.
// 2. for 문의 초기 선언문 쪽에서 x 값을 선언하면, 전역 변수로 var x 를 선언하지 않아도 되어 메모리가 더 효율적이게 된다. for (var i = 0, x = treasureChest.necklaces.length; i < x; i++) { console.log(treasureChest.necklaces[i]); }
- 주의할 점 : 자바스크립트는 {} 로 스코핑이 되어 있지 않기 때문에, 위의 for 반복문이 끝나면 x 값은 최종 값으로 할당되어 있다는 사실
-
또 다른 개선 포인트
// 3. 각 반복 싸이클마다 treasureChest 객체의 속성에 접근을 할 필요가 없다. var list = treasureChest.necklaces; for (var i = 0, x = treasureChest.necklaces.length; i < x; i++) { console.log(list[i]); }
모든 인덱스를 접근할 때에는
for loop
문이 좋고, 때로는for in
보다 성능이 나은 경우가 있다.for in
은 prototype 에 접근하여 기존의 기 정의된 메서드까지 포함하여 출력하므로 비효율적
Performance (Script Loading)
- Work Intensive javascript 는 body 마지막 태그 맨 위나 async 속성 이용하여 페이지 첫 로딩을 빠르게 한다.
Performance (Inheritance)
- 자바스크립트에서 상속은 prototype 을 이용
-
공통으로 쓰는 메서드는 모두 prototype 에 집어 넣는다.
function SignalFire(id, logs) { this.id = id; this.logs = logs; this.functionality1: function() { }, this.functionality2: function() { }, this.functionality3: function() { }, }
- 위 함수의 경우 매번 객체를 생성할 때 마다 사용하지 않는 메서드들을 메모리에서 사용하는 낭비가 발생한다.
- 따라서, 매번 객체 생성시 필요한 속성이나 메서드만 가져가도록 하고, 공통 메서드는 다음과 같이 prototype 으로 뺀다.
SignalFire.prototype = { functionality1: function() { }, functionality2: function() { }, functionality3: function() { }, }
Performance (Indivdual DOM)
- list 를 배열로 갖는 DOM 요소에
append
메서드를 이용하여 DOM 을 추가하면 전체 리스트가reflow
된다. 이는 성능에 악영향을 준다. -
성능 향상을 위한 해결법은 Fragment 를 사용한다.
var fragment = document.createDocumentFragment(); fragment.appendChild(element); list.appendChild(fragment);
Performance (Get rid of var redundancy)
-
var 지정어를 사용할 떄, 다음과 같이 코드량을 줄일 수 있다.
var a = 1; var b = "hello"; var c = ["a","b","c"]; var a = 1, b = "hello", c = ["a","b","c"]; // 코드의 가독성이 높아지고, 간결하다.
Performance (String Concatenation)
-
문자열의 길이에 따라
+=
연산자와join()
메서드의 성능차이가 발생한다.- 문자열이 짧을 떄 :
+=
연산자가 성능이 더 빠르다. - 문자열이 길고, 문자열이 배열안에 리스트 형태로 저장되어 있을 때 :
join("\n")
메서드가 성능이 우월하다.
var page = ""; for (var i = 0, x = newPageBuild.length ; i < x ; i++) { page += newPageBuild[i]; } // join() 메서드 활용 page = newPageBuild.join("\n");
- 문자열이 짧을 떄 :
Namespacing
- 팀 프로젝트 시 많은 양의 자바스크립트 코드를 작성할 때, 타 팀원이 작성한 전역변수가 overwrite 되는 경우가 발생한다.
-
이를 막기 위해 namespacing 을 활용한다.
var a = ["Apple", "Banana", "Coil"]; var c = function () { console.log("this is not what I want."); }; var nameSpace = { a : "1", b : 23, c : function() { // ... } }; // HTML Element click event onClick=nameSpace.c();