지금까지 언어의 첫장을 넘기면서 무심코 지나갔던 부분들에 대해서 많은 것을 확인 하고 있다.

이 글은 Javascript 에 대한 글이고 나름의 성능에 대한 글이기도 하다.

하지만 전문적이지는 않고 대략적인 논리로 성능에 접근한다.

자료형

자바스크립트에는 많은 자료형이 있고 기본적으로 모두 객체이다.

원시 타입의 자료형이 있고 (변하지 않는)

  • Number
  • Boolean
  • Null
  • Undefined
  • String

원시 타입을 모아서 저장할 수 있는 자료형이 있다. (변할 수 있는)

  • Object
  • Array
  • Function

심지어 Function 도 객체이다. (first-class object 라고 하는)

변수

변수는 자료형을 담는 메모리 공간이다. 담아야 하는 값에 따라 그 크기가 달라진다.

자바스크립트에서는 변수 선언할 때 자료형을 지정하지 않기 때문에 초기화 하는 값에서 최초 메모리 공간이 설정된다.

즉, 변수는 초기화를 잘 해줘야한다.

변수에서 초기화를 한다는 것은 정확한 자료형으로 메모리 공간을 확보한다는 의미다.

그렇게 되면 브라우저는 그 자체로 최적화를 할 수 있다.

var a;    //  이렇게만 선언 해놓으면 무엇을 저장할지 브라우저는 모른다. 

var b = 0;  // 이렇게 설정하면 브라우저는 최초 메모리 공간을 Number 객체 기준으로 맞출 수 있다.

변수는 언제 선언하는가?

javascript 는 변수를 아무 곳이나 선언할 수 있다.


var a = 10;   // 그냥 global 변수로 선언 

for(var i = 0, len = 10; i < len; i++) {  

}

function B() {
  var a = 20;       // 함수 안에서 사용될 변수 선언 
}

이렇듯 아무곳에서나 선언을 하고 변수를 사용할 수 있는 이점이 있다.

Scope (변수가 가지는 접근 영역)

하나의 변수는 자신의 Scope 를 가진다.

어디서든 접근할 수 있는 global 영역 또는 특정 블럭안에서 접근 할 수 있는 local 영역을 가진다.

변수를 어디에 선언하느냐에 따라 변수에 접근할 수 있는 scope 가 달라지게 되는 것이다.

scope 에 따라 메모리에 상주할 수 있는 주기가 결정된다.

global 영역은 계속 적으로 메모리에 있을 것이고

local 영역은 local 영역의 코드 블럭이 변수는 더이상 사용되지 않기 때문에 사라질 것이다.

local 영역이라고 해도 특정 객체를 global 영역에 저장해놓으면 그 객체는 사라지지 않는다. (정확히는 언제 사라질지 알 수 없는 )

Boolean

true 또는 false 를 표현한다.

Null

null 이라는 값을 가진다. 딱 한가지 값만 가진다.

Undefined

undefined 라는 값을 가진다. Null 과 마찬가지로 한가지 값만 가질 수 있다.

Number

숫자를 표현한다. 정수(Integer)가 될 수도 있고 실수(Float)가 될 수도 있다.

String

말 그대로 문자열이다. 다만 한번 생성된 문자열은 변경할 수가 없다(Immutable).

String 객체의 메소드로 조작되는 모든 값들은 새로운 문자열을 다시 만들어서 리턴한다.

Object

자바 스크립트는 Object 를 쉽게 만들 수 있다.

var o = new Object();   // 기본 Object 클래스의 instance를 만든다. 

var o = { json : true }; // 위와 비슷한 역할을 한다.

두 구문 모두 메모리에 객체애 대한 공간을 만든다.

자신만의 객체를 정의하고 싶으면 Function 을 사용하면 된다.

function A() {

}

var a = new A();    // A 라는 class 의 instance 를 생성했다. 

//비슷하게 new 가 없어도 된다. 
var a = A();

function 을 만들고 new 라는 키워드로 instance 를 생성하게 된다.

Function

특정 로직을 담고 있는 코드 블럭이다.

함수는 2가지로 선언 할 수 있다.

function Z() { }  // 이름이 있는 함수와 

var Z = function () { }  // 이름이 없는 함수로 선언 할 수 있다.

함수도 하나의 자료형이기 때문에 어떠한 변수에 들어가도 이상할게 없다. 다만 이름이 있는 것과 없는 것은 차이가 조금 있다.

이름이 있는 것은 javascript를 파싱할때 브라우저에서 함수를 미리 올려놓는다.

해당 스크립트가 모두 파싱이 된 상태가 되면 이름 있는 함수는 바로 사용할 수 있다.

하지만 이름 없는(익명) 함수는 함수를 선언하는 시점까지 가야만 사용할 수 있다.

A() ;           // A 라는 함수를 사용할 수 있다. 
function A() { }   // 파싱하면서 메모리에 올리니깐. 

// 하지만 아래와 같이는 되지 않는다. B 라는 함수가 실행시점에 없고 그 뒤에 생성되기 때문이다. 
B();
var B = function () { }

Array

여러개의 데이타를 동시에 가지고 있을 수 있는 자료형이다.

array 는 다음과 같이 사용할 수 있다.

var arr = [];           // 비어있는 Array instance 를 만든다. 

var arr = [0, 1, 2, 3]; // 4개의 요소가 있는 Array instance 를 만든다. 

var arr = new Array(4); // 비어있는 Array instance 를 만든다. 

var arr = new Array([0, 1, 2, 3]); // 4개의 요소가 있는  Array instance 를 만든다.

array 도 자료형이기 때문에 어디든 선언해서 사용할 수 있다.

최초 선언할때 지정된 메모리 공간이더라도 몇가지 함수를 통해서 요소를 계속 늘려갈 수 있다.

arr.push(0);  // 마지막에 0 값을 추가한다. 
arr.shift();  // 처음값을 빼고 배열을 재구성한다.
arr.unshift(0);  // 배열 처음에 0 값을 추가한다. 
arr.pop(); // 마지막 요소를 제거한다.

위에는 간단한 몇가지 메소드만 나열 했는데 이것 말고도 무수히 많은 메소드를 가지고 배열을 조작할 수 있다.

배열을 잘 활용하면 중복으로 어떤한 로직을 처리할때 아주 편리하다.

변수에 선언된 자료형을 바꿀 수 있는가? (Type Casting)

javascript 는 자료형을 선언하지 않기 때문에 변수가 중간에 어떠한 값으로 변해도 상관 없다.

자료형을 바꿀 수 있는 몇가지 팁을 소개한다.

// 문자열을 숫자로 바꾸고 싶을 때 
parseInt("10");
parseInt("10", 2); // 2진수로 변환 
parseFloat("10.5");   // 실수 형태로 변환 

// 더 쉬운 방법이 있다. 
+"10"  // 자동으로 실수가 된다.
// 숫자를 문자열로 바꾸고 싶으면 
10 + ""   // 문자열을 더하면 된다.  문자열과 더해지는 모든 자료형은 문자열이 된다.
// 값을 boolean 형태로 변환하기 
!!10      // 10 이란 값을 boolean 값으로 변환한다.  여기서는 true 가 되겠다.

변수는 데이타를 담고 있다. 잘 써야한다.

지금까지 설명했던 모든 것들은 데이타를 담는 변수에 관련된 것이다.

데이타를 담는 다는 것은 메모리 공간을 사용한다는 의미이고 이것은 메모리 공간에 대한 비용과 메모리 공간을 확보하기 위한 코드를 실행하는 시간에 대한 비용을 야기시킨다.

공간을 확보하기 위해 시간을 소모하기 때문에 잘 써야한다. (물질과 시간을 동시에 사용하는)

Javascript 는 Interpreter

변수는 어떻게 잘 써야할까?

변수를 잘 쓰는 방법의 기본 컨셉은 메모리 공간을 작게 확보하고도 같은 로직을 수행하는 것이다.

그렇게 할수 있다면 좀 더 많은 자원을 아낄 수 있고 자원의 생성시간도 줄일 수 있다.

자료형

초기화

var a;

...

a = 10;

자료형은 var 라는 키워드로 선언을 할 때 지정해두자.

초기화를 하지 않으면 undefined 이라는 객체가 되고 그 다음에 다시 특정 값에 대한 메모리로 설정하기 때문에 메모리 설정을 두번 하게 된다.

var a = 10;

한번으로 끝내보자.

동적으로 자료형 바꾸기

var a = 0;
// 특정 영역 실행 이후 배열로 변환 
a = [0];

a 라는 변수가 Number 가 되었다가 다시 배열로 바뀌었다. 초기화 한 메모리와 다른 메모리가 설정이 되면 그만큼 다시 그 시점에 작업을 더 해야한다는 의미가 된다.

그리고 중간에 자료형이 바뀌는 것은 로직을 이해하기 힘들게 할 수 있다.

var a = 0, b; 

b = [0];

선언을 따로 하는게 좋을 듯 하다.

배열도 초기화 하자.

var a = [];           // 이렇게 초기화 하면 배열에 대한 메모리 할당을 4번을 해야한다. 
a[0] = 0;
a[1] = 0.5;
a[3] = "xxx";
a[4] = new Object();

var a = [0, 0.5, "xxx", new Object()];   // 이렇게 하면 한번만 하면 된다.

배열의 개수를 미리 알 수 있다면 아래도 좋은 선택이다. 다만 사용하지 앟는 공간이 생길 수 있다.

var a = new Array(5);       // 5 개 메모리를 미리 확보한다.

loop 에서 변수 선언

아래 두가지 for 문을 보자.

// for 문 안에 선언한 경우 
var arr = []; 
for(var i = 0, len = 10; i < len; i++) {
  var value = f(i);

  arr.push(value*2);
}


// for 문 밖에 변수를 선언하는 경우 
var value = 0;
var arr = []; 
for(var i = 0, len = 10; i < len; i++) {
  value = f(i);

  arr.push(value*2);
}

얼핏보면 별 차이가 없어 보인다. 하지만 for 문 안에서 변수를 선언하는 경우는 변수 선언은 루프가 돌아간 만큼하게 된다.

그 말은 메모리 공간을 확보하는 작업을 루프만큼 하는 것이다.

하지만 외부에 변수를 선언하게 되면 한 번만 하고 끝난다.

되도록이면 루프 안에서 초기화를 하지 말자. ~

함수 정의 안에서 변수

상수로 사용하는건 외부 변수로 빼자.

function A(a, b) {
  var c = 10;       // 함수가 실행될때마다 c 라는 변수에 10 을 할당한다.

  var d = a * c + b;
}

var c = 10; 
function A(a, b) {
  //var c = 10;       // 외부에서 한번만 할당하기 때문에 이 부분이 필요없어졌다. 
  var d = a * c + b;  
}

만약 A라는 함수가 loop 안에서 실행되는 함수면 loop 가 도는 만큼 변수도 생성을 반복해야한다.

내부 변수를 객체로 초기화해야할 경우

function A(a, b) {
  var c = new Object();   

  return c;               // 배열이나 객체의 값을 리턴하게 될 때 
}

만약에 이런 경우라면 실제 리턴되는 객체가 언제까지 남아있을 수 있는지 확인해봐야한다.

잘 못하면 memory leak이나 지속적인 gc 의 대상이 될 수 있다.

gc 관련해서는 다음에 따로 다룰 예정이다.

function A() {
  function B() {    // 함수 안에서 함수 선언 

  }

  B();
}

함수 안에서 함수 선언은 특정 로직을 숨길 때 많이들 사용한다.

하지만 B 라는 함수 선언 자체가 A 함수가 실행될때마다 이루어 지기 때문에 결국 loop 안에서는 별로 좋은 선택이 아닐 수 있다.

되도록이면 loop 안에 사용될 함수들에 대해서는 내부에 함수 정의를 하지 말자.

함수를 정의를 하는 것은 결국은 Function 객체를 생성하는 것과 같기 때문에 매번 B 라는 객체를 생성하는 것과 같다.

변수는 선언만 잘 해도 많은 자원 소모를 줄 일 수 있다.

results matching ""

    No results matching ""