2010/10/26 23:34

일반적으로 개발자들은 자바스크립트를 사용할 때 성능을 생각하고 코딩하는 경우는 거의 없습니다.
하지만 코딩을 하다보면 가끔씩 많은 정보를 자바스크립트로 제어해야 할 경우가 있습니다. 특히 Enterprise Solution을 개발할 때 이런 상황을 자주 직면하게 됩니다.
그래서 간단하지만 효과적인 javascript 성능향상 팁을 정리해 보았습니다.


Tip 1. 반복문
여러분은 반복문을 사용하실 때 어떤 구문을 사용하시나요?
보통 가장 기본적인 아래와 같은 반복문을 가장 많이 사용하실겁니다.

for(i=0; i<array.length; i++)

이 반복문은 책이나 예제로 많이 사용되어 집니다.
하지만 이 반복문에는 단점이 하나 있습니다. 그것은 이 구분을 반복할 때 마다 array.length 메소드가 매번 호출된다는 점입니다.
while 문에서도 아래와 같이 사용하면 array.length가 매번 호출됩니다.

i=0; while(i<array.length)

이 부분에서 성능을 향상하기 위해서는 아래처럼 array.length를 꼭 변수에 담아 사용하시기를 권합니다.
var cnt = array.length;
for (i=0; i<cnt; i++)



Tip 2. + 연산자
var str;
for (i=0; i<10000; i++) {
str += 'prefix'+i+'suffix';
}

위 구문은 반복 횟수가 적을 때는 아무런 문제가 없습니다. 하지만 1000건을 넘어가면 몇 초동안 화면이 굳어버리게 됩니다.
이럴 경우에는 array와 join메소드를 사용하시면 됩니다.

var strArray = [];
for (i=0; i<10000; i++) {
strArray.push('prefix', i, 'suffix');
}
var str = strArray.join('');

이 방법을 사용하게 되면 +를 사용할 때 보다 훨씬 빠른 결과를 얻을 수 있습니다.



Tip 3. DOM : createElement(), appendChild()

var lo = document.createElement('lo');
for (i=0; i<100; i++) {
lo.appendChild(document.createElement('li'));
}
document.body.appendChild(lo);

위 예제에서는 lo 객체에 childNode로 li 100개를 생성하고 있습니다.
이 예제에서 개선될 점은 두 가지 입니다.
하나는 반복문 안에서 appendChild를 사용했다는점이고 두 번째 역시 반복분 안에서 createElement를 사용했다는 점입니다.
위 예제를 개선하면 다음과 같습니다.

var lo = document.createElement('lo');
var arrayLi = [];
for (i=0; i<100; i++) {
li.push('<li>', '</li>');
}
lo.innerHTML = li.join('');
document.body.appendChild(lo);

appendChild 대신 2번 팁이 사용되었군요. 그리고 createElement가 아니라 innerHTML이 사용되었습니다.
이 방법은 appendChild, createElement로 인해 발생되는 부하를 극적으로 줄여주게 됩니다.
저는 이 방법을 통해서 2분이 걸리던 작업을 10초만에 나오도록 개선한 적이 있습니다.





그리고 이보다 훨씬 많은 성능향상팁이 있지만 가장 효과적인 세 가지만 적어보았습니다.
다른 팁들은 성능 향상의 폭이 적어서 거의 극한 튜닝에나 쓰일법한 기법이 많고 또 브라우저 마다 효과가 약간씩 다르기 때문 입니다.

주의하실점은 이 팁들은 IE6에서 가장 큰 효과가 있습니다. 하지만 IE8이나 최신버전의 chrome, FireFox등에서는 거의 차이가 없습니다.
직접 테스트를 해보고 싶으시면 http://spoon.net/Browsers/ 에서 여러가지 브라우저를 실행한 후 아래 페이지를 방문해 보세요.
저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License
2009/01/13 23:24

 함수 function

 자바스크립트는 숫자, 문자열, 부울값등 기본적은 데이터형을 지원할 뿐만 아니라,
 기본 데이터 집합체인 객체(object)와 배열(array)등 두가지 복합 데이터 형(complex data type)도 지원한다.
 대부분의 언어와 달리 자바스크립트는 데이터 형으로서 함수도 지원하여 자바스크립트 프로그램을 문자열처럼 취급할 수 있게 해준다.
 함수가 변수, 배열, 객체에 저장될 수 있고, 함수가 인자로 다른 함수에 전달 될 수 있다.
 함수가 객체의 프로퍼티에 할당되는 경우에 이 함수를 객체의 메소드라고 한다.
 자바스크립트의 함수는 구문일 뿐만 아니라 데이터이기도 하다
 
 - 함수 호출 연산자 () : 고정된 피연산자 개수를 가지고 있지 않다.
 
 - 자바스크립트에서 문장은 프로그램에서 동적인 동작을 수행하는 반면 함수 정의는 프로그램의 정적인 구조를 나타낸다.
   문장이 실행 시간(runtime)에 수행되는 반면 함수는 자바스크립트 코드가 파싱되거나 컴파일될 때 정의된다.
   자바스크립트 파서가 함수 정의를 만나면 그것은 함수의 본문을 구성하는 문장을 파싱하고 저장한다. (실행하지는 않는다.)
   그리고 나서 그 함수를 나타내는 이름과 같은 이름의 프로퍼티를 정의한다.





    alert(f(4));      // 16을 출력한다. f()는 그것이 정의되기 전에 호출쇨 수 있다.

                        // 단, 이벤트 핸드러에서 함수를 호출할 경우에는 미리정의 되어 있어야 한다.
    var f=0;          // f의 프로퍼티를 재설정한다.
    function f(x){  // 이 문장은 위 두 행이 실행되기 전에 함수 f를 정의한다.
       return x*x;
    }
   alert(f);           // 0을 출력한다. f()는 변수 f에 의해 재설정 된다.





    위와 같은 결과가 나온 이유는 함수 정의가 변수 정의와 다른 시점에 발생하기 때문이다.


 -  a.sort(function(a,b){return a-b;});      // 함수를 정의하고 그것을 다른 함수에 전달
    var s = (function(x){return x*x;})(10); // 정의와 호출을 동시에

 arguments 객체 - 함수의 인자

arguments는 arguments 객체를 참조하는 호출 객체의 특정한 프로퍼티이다.
- arguments[] 배열의 요소는 함수에 전달된 인자의 값을 가지고 있다.
- 인자에 이름이 없더라도 해당 인자의 값에 접근할 수 있게 해준다. ex) arguments[0]


 콜백 함수

메소드 실행 시에 자동으로 호출되는 함수가 있다. 그러한 메소드로 filter, forEach, every, map, some이 있으며,

이때 사용되는 함수는 함수 리터럴로 일반적으로 콜백 함수라고 한다.


 함수 클로저

자바스크립트 프로그램에서는 새로운 영역을 생성할 때마다 이를 둘러싸기 위한 '연관 영역 버블'이 생성된다.

이는 함수에도 적용되며, 해당 함수는 자신의 영역에서 동작하게 된다.





function outFunc(base){   // 바깥쪽 함수

      var punc = "!";

      function inFunc(ext){   // 안쪽 함수

             return base + ext + punc;

      }

      return returnString;

}





일반적으로 함수가 종료되면, 그 영역에서 해제된다. 왜냐하면 더 이상 필요치 않기 때문이다.

하지만 안쪽 함수의 경우엔 이것이 바깥쪽 프로그램에 반환되고 외부 변수에 할당된다.

즉, 안쪽 함수의 영역이 바깥쪽 함수의 영역에 추가되고, 결국 호출 프로그램에 추가되는 것이다.

따라서 함수 리터럴 및 바깥쪽 함수의 인자와 변수를 유지하게 된다. 다른 함수 내에서 내부 객체로 생성된

함수 리터럴을 반환하여 호출 프로그램에서 이를 변수로 배정한 것을 자바스크립트에서는 클로저(closure)라고 한다.

즉, 함수가 동자하는 데 필요한 데이터 영역이 확장되는 것이다.

 

 

 

 callee 프로퍼티
현재 실행되고 있는 함수를 참조, 이름이 없는 함수가 자기 자신을 호출할 때 유용하다.





 function(x){
    if(x>1) return x * arguments.callee(x-1);
    return x;
  }




 caller 프로퍼티
현재 호출된 함수를 참조하는 것이 아니라 현재 호출된 함수의 arguments 객체를 참조한다.
 

 apply() 메소드
함수를 마치 다른 객체의 메소드처럼 호출할 수 있게 해준다.




 객체 object

이름이 지정된 데이터의 여러 가지 부분을 포함하는 데이터 구조로, 이 데이터를 처리하기 위한 여러가지 메소드도 포함한다.
객체는 관련된 데이터 값과 메소드를 사용하기 쉽게 단일 패키지 안에 모아두기 때문에 코드의 모듈성(modularity)과
재사용(reusability)을 증가시켜서 전반적으로 쉽게 프로그램을 작성할 수 있다.


- 객체 == 이름과 값을 가진 '프로퍼티(property)'의 집합
- 자바스크립트에서 객체는 임의의 수만큼 프로퍼티를 가질 수 있고, 객체에 동적으로 프로퍼티를 추가할 수 있다.


 

 객체생성 연산자 new

 - 객체 생성 var obj = new Object();
(delete : 객체의 프로퍼티, 배열의 요소를 삭제하거나 정의되지 않은 값으로 만든다.)
 

 객체접근 연산자 . / []

- [] 연산자를 사용하면 배열의 요소에 접근할 수 있고 객체의 프로퍼티에도 접근할 수 있다.


 생성자

자바스크립트에서는 new 연산자와 미리 정의된 Object(), Date(), Function() 같은 함수들을 이용하여

새로운 객체를 만들거나 초기화 할 수 있다. 그러나 사용자가 직접 객체형을 정의하여 사용하는 경우가 더 많다.
예를 들어, 사각형을 처리하는 Rectangle 클래스에 width, height 프로퍼티가 있을때,
width, height 같이 이미 정의된 프로퍼티를 가지는 객체를 생성하려면 새로운 객체를 생성하고
이 프로퍼티들을 초기화 할 수 있는 '생성자(construnctor)'가 필요하다.

- 생성자는 new 연산자를 통해 호출된다.
- 생성자는 this라는 특수 키워드의 값으로 새롭게 생성된 빈 객체의 참조를 넘겨 받아서  새로은 객체를 적절하게 초기화 한다.





// 생성자 함수 정의
  function Rectangle(w, h){
   this.width = w;
   this.height = h;
  }

// 객체를 생성하기 위해 생성자 함수를 호출, w, h를 전달해서 새로운 객체를 적절한 값으로 초기화한다는 것을 주의

var rect1 = new Rectangle(2,4);




- 생성자 함수는 일반적으로 반환 값이 없으며 this 값으로 넘겨받은 객체를 초기화하고 아무값도 반환하지 않는다.
  그러나 객체를 반환할 수는 있으며 그럴 경우에 반환되는 객체는 new 표현식의 값이된다. 이 경우에 this의 값의 객체는 버려진다.


 메소드 method
객체에서 호출되는 함수


 prototype 프로퍼티

모든 함수에는 미리 정의된 '원형(prototype) 객체'를 참조하는 prototype 프로퍼티가 있다.
모든 객체는 원형을 가지므로 객체는 그것의 원형이 가진 프로퍼티를 모두 상속받는다.
이는 객체의 모든 프로퍼티가 그것을 상속한 객체의 프로퍼티처럼 보인다는 의미이다.
객체의 클래스에 대한 원형 객체를 지정하려면 적절한 객체에 생성자 함수의 prototype 프로퍼티의 값을 설정한다.
그 다음에 생성자로 새로운 객체를 호출할 때 자동으로 자바스크립트는 지정한 객체를 새로 생성되는 객체의 원형으로 사용한다.


 - 생성자 함수는 객체의 클래스를 정의하고, 클래스의 상태 변수로 사용되는 width, height 같은 프로퍼티를 초기화 한다.
   원형 객체는 생성자와 결합하므로 클래스의 각 멤버들은 원형으로부터 정확하게 똑같은 프로퍼티 집합을 상속받는다.
   이는 원형 객체가 메소드나 다른 상수 프로퍼티를 정의하기에 가장 이상적인 위치라는 것을 의미한다.


 - 상속(inheritance)은 프로퍼티 값을 검색하는 과정의 일부로서 자동으로 발생한다.
   프로퍼티는 원형 객체로부터 새로운 객체로 복사되는 것이 아니며 단지 해당 객체의 프로퍼티인 것처럼 보이는 것 뿐이다.


 - 원형 객체를 사용하여 프로퍼티를 상속할 수 있으므로 각 객체를 만들 때 필요한 메모리의 양을 크게 줄일 수 있다.


 - 객체는 생성된 후에 원형에 추가된 프로퍼티 값도 상속받을 수 있다.


 - 각각의 클래스에는 하나의 프로퍼티 집합을 가진 하나의 원형 객체가 있다.
   그러나 이 클래스로부터 많은 인스턴스를 만들 수 있고, 각 인스턴스에서는 원형의 프로퍼티를 상속받게 된다.
   객체 o의 프로퍼티 p를 읽을 때 자바스크립트는 먼저 o에 p라는 프로퍼티가 있는지 검사한다.
   p가 없는 경우에는 o의 원형 객체에 p라는 이름을 가진 프로퍼티가 있는지 검사한다.
   이것은 원형을 바탕으로 한 상속 작업이다.


  프로퍼티 상속은 프로퍼티 값은 읽을 때만 발생하고 프로퍼티 값을 쓸 때는 발생하지 않는다.
   원형으로 부터 프로퍼티를 상속받은 객체 o에서 프로퍼티 p의 값을 설정하면 객체 o에서 직접 "새로운 프로퍼티 p가 생성"된다.
   이렇게 되면 객체 o는 p라는 이름이 지정된 자신만의 프로퍼티를 가지게 되고, "그 결과로 객체의 원형으로부터 p의 값을
   더이상 상속 받을 수 없게 된다." (이때 원형의 프로퍼티 p는 가려진(shadow), 숨겨진(hide) 프로퍼티라고 부른다.)


 
 인스턴스 instance

클래스에 기초한 객체지향 언어와 자바스크립트에서는 같은 클래스에 여러 객체를 사용할 수 있다.
이런 객체를 클래스의 인스턴스라고 한다. == 클래스 안의 객체

- 인스턴스 변수
  모든 객체에는 자신만의 분리된 인스턴스 변수 복사본이 있다. 다시 말해 어떤 클래스에 10개의 객체가 있다면
  10개의 인스턴스 변수가 있는 셈이다.  예를 들어 Circle 클래스에서 모든 circle 객체에는 원의 반지름을 정의하는 프로퍼티 r이 있다.
  이런 경우에 r은 인스턴스 변수이다.

   각 객체에는 자신만의 인스턴스 변수 복사본이 있으므로 각각의 객체를 통해 이 변수에 접근할 수 있다.
   객체의 프로퍼티 == 인스턴스 변수
 
- 인스턴스 메소드
  인스턴스 메소드는 this 키워드를 사용하여 처리하고 있는 객체나 인스턴스를 참조한다.
  클래스의 모든 인스턴스에서 호출할 수 있지만 이것이 인스턴스 변수처럼

  모든 객체에서 자신만의 메소드 복사본을 가진다는 의미는 아니다.

  대신에 모든 클래스의 인스턴스는 인스턴스 메소드를 모두 공유한다.


 


 garbage collector
자바스크립트에서는 수동으로 메모리를 반환하는 대신에 이 작업을 '가비지 수집(garbage collection)'이라는 기술에 맡긴다.
인터프리터는 프로그램에서 더 이상 쓰이지 않는 객체를 검색할 수 있다.
객체가 접근하기 어려운 위치(프로그램에서 변수가 더 이상 그 객체를 참조하지 않을 경우)에 있으면
인터프리터는 그 객체가 더 이상 필요하지 않다고 판단하고 그 객체에 사용된 메모리를 해제한다.





 var s = "hi";    // 문자열에 메모리를 할당
 var u = s.toUpperCse(); // 새로운 문자열을 생성
 s = u;     // 원래 문자열에 참조를 엎어씀




           이 코드가 실행된 후에는 원래 문자열 "hello"에 더 이상 접근 할 수 없다.


 - 가비지 콜렉터 대부분은 '표시, 제거(mark and sweep)' 라고 알려진

   기본적인 가비지 콜렉션 알고리즘을 약간씩 변형시켜서 사용한다.


 표시, 제거 mark and sweep

- 주기적으로 자바스크립트 환경에서 사용되는 모든 변수 목록을 검색한다.
   그리고 이 변수들이 참조하는 값에 표시를 한다.

   참조한 값이 객체나 배열이면 가비지 수집기는 그 객체의 프로퍼티나 배열의 요소에 표시를 한다.

   가비지 수집기는 값들로 이루어진 그래프와 트리를 순환적으로 검색하여 사용되고 있는 각각의 값에 표시를 할 수 있다.

   이러한 작업을 마친 후에 표시되지 않은 것은 가비지가 된다.


- 표시, 제거 가비지 수집기가 현재 사용되고 있는 값에 표시하는 작업을 끝낸 후에는 제거 단계를 수행한다.
   이 단계를 진행하는 동안 그 환경에서 사용되는 모든 값 목록을 찾고, 표시되지 않은 것에 할당되었던 메모리를 반환한다.
   전형적인 표시, 제거 가비지 수집기는 표시 작업과 제거 작업을 동시에 한다.
   이러한 작업은 가비지 수집을 수행하는 동안 시스템의 성능을 현저히 떨어뜨린다.
   좀더 정고하게 변화된 알고리즘은 상대적으로 작업을 효율적으로 처리하며, 시스템의 성능을 저하시키지 않고
   백그라운드에서 수집 작업을 수행한다.
 



 기본형과 참조형

 

자바스크립트에서 데이터 형은 크게 두 가지로 분류되는데, 그것은 바로 기본형과 참조형이다.


- 기본형(primitive type) - 숫자, 부울값, null, 정의되지 않은 값 등

var a = 1;

var b = a;

a = 2;

alert(b); -> 1을 출력 한다. a변수가 b 변수에 복사 되었기 때문이다.

- 참조형(reference type) - 객체, 배열, 함수 등

 function movie(){
    this.name = 'none';
 }

 var movieA = new movie();
 var movieB = movieA;
 movieB.name = "111";
 alert(movieA.name);  -> 111을 출력한다. movieA 오브젝트와  movieB 오브젝트가 같은 곳을 참조하고 있기 때문이다.


크리에이티브 커먼즈 라이선스
Creative Commons License