2015년 3월 3일 화요일

[JavaScript] 자바스크립트의 객체와 원시자료형, 그리고 함수의 매개변수(Function Argument)

자바스크립트(ECMAScript)의 변수는 타 프로그래밍 언어에 비해 매우 자유로운 선언과 사용이 가능하다. C#이 .Net Framework 3.5에서야 구현한 Var 키워들 자바스크립트(ECMAScript)는 태생부터 가지고 있었고, 이로 인해 var 키워드 하나로 각기 다른 타입의 데이터들을 쉽고 간단하게 다룰 수 있게 만들었다.
변수에 대해 잠시 다뤄보자. 우리가 선언하는 변수(Variable)들은 선언과 초기화시 특정 메모리(RAM) 영역을 가리키게 된다. 말인즉,


var a = 1;
var b = "TEST";


위와 같이 변수 a 와 b 를 선언할 때, 메모리 영역에서는 ECMAScript 코어 엔진이 사용되지 않는 영역에 1과 "TEST"라는 값을 저장하게 되고, a 와 b 같은 변수 이름은 그져 그 메모리 영역을 가리키는데 사용될 뿐인 것이다. 이 때문에 변수의 값과 또는 타입은 스크립트가 실행되는 와중에도 언제든 변경이 가능하게 되는것이다.

여기서 문제는, RAM 메모리가 무한하지 않다는 것인데, 그렇기 때문에 메모리가 할당되기만 하고 할당된 메모리를 다시 풀어주지 않는다면 스크립트가 실행되고 새로운 변수가 선언될 때마다 메모리가 서서히 차버리고 결국에는 "Out of Memory"가 생기고 실행중인 프로그램이 크래쉬 되버릴게 분명하다. 여기서 바로 Scope(변수 영역)의 개념이 등장하게 된다. 변수 영역(Scope)이란 변수가 사용되는 영역을 가리킨다, 즉 이러한 영역의 스크립트 실행이 모두 끝나게 되면, 당연하게도 그 변수는 더 이상 사용되지 않게되니, 할당된 메모리를 풀 수 있게 된다.

다시 자바스크립트로 돌아가자. 자바스크립트(ECMAScript)의 Data Type은 크게 2가지 종류로 나뉜다, Primitive Data Type(원시 자료형)과 Composite/Reference Data Type(객체). Primitive Data Type 에는 String(문자열), Number(숫자), Undefined, Null, Boolean, 이렇게 총 5개의 자료형이 존재한느데 이 자료형들의 공통점은 모두 다 변수 선언(Declaration), 초기화(Initialization), 어싸인(Assign)시 값이 저장된 메모리 영역에 직접적으로 접근한다는건데, 즉 변수에 새 값이 어싸인 될 시에 변수에 할당된 메모리 블럭에 저장된 값을 바로 변경한다는 뜻이다, 이 때문에 이런 Primitive Data Type 들은 Access By Value의 속성을 가지게 된다. 아래 코드를 보자


var a = 33;
var b = a;
b = 44;

console.log(a); // 33
console.log(b); // 44


위의 코드에서는 총 3개의 변수가 선언됬다. a, b, 그리고 c. 자바스크립트에서의 메모리 할당은 변수 초기화(Initialization)시 일어나게 된다. 즉 = 이라는 키워드가 변수에 처음 사용될 때만 메모리가 할당된다는 말이다. 우선 a 라는 변수에 33이라는 숫자를 저장했다. 이는 a 라는 변수에 할당된 메모리에 바로 저장되게 된다.

그렇다면 b 라는 변수는 어떨까, "var b = a" 구문은
b라는 변수가 a 라는 변수를 저장하게 된다고 말하고 있다. 하지만 실제로 변수 b는 자신에게 할당된 메모리 블럭에 변수 a(또는 변수 a가 저장된 메모리 블럭 주소)를 저장하는것이 아닌 변수 a의 메모리 블럭에 저장된 값을 저장한다. 즉 변수 a 에게 할당된 메모리 블럭을 복사해서 자신의 메모리 블럭에 덮어 씌운다는 말이다.

이때문에 b = 44 라는 구문을 이용해서 b에 새로운 값을 어싸인 해주거나, a 의 값을 변경하더라도 다른 변수의 값은 변하지 않게 된다. 즉 변수 a 와 변수 b를 저장하는데 2개의 메모리 블럭이 할당 된것이다.

하지만 Composite/Reference Data Type, 주로 객체라 불리는 이 자료형은 어떻게 될까?

Primitive Data Type 과 Composite/Reference Data Type의 가장 큰 차이는 바로 Primitive Data Type 이 변수의 값을 저장할 때, Composite/Reference Data Type은 변수의 값이 저장된 힙(Heap) 메모리의 주소값을 저장한다는 것이다. 즉 Primitive Data Type이 변수에 할당된 메모리 블럭과 바로 연결되있다면, Composite/Reference Data Type은 변수의 값이 저장된 메모리 블럭의 주소를 가지고 있고, 자바스크립트 엔진이 변수가 가지고 있는 메모리 주소를 이용해서 변수의 값에 접근한다는 뜻이다. 이렇한 이유로, Composite/Reference Data Type은 Access By Reference 의 속성을 가지고 있다.


var a = {
 name : "Object a",
 message : "This is Object a"
};
var b = a;
b.name = "Object a changed to Obejct b";

console.log(a);
// { name: 'Object a changed to Object b',
//  message: 'This Object is changed to b' }
console.log(b);
// { name: 'Object a changed to Object b',
//  message: 'This Object is changed to b' }


변수 a 는 초기화(Initialization)시 Heap 메모리에 생성된 객체의 메모리 주소를 저장하게 된다. 그리고 var b = a 라는 구문에서, 변수 a 초기화시 생성된 객체를 변수 b 에 복사하는게 아닌, a가 가진 메모리 주소, 즉 그 객체를 가리키는 메모리 주소를 복사하게 되는 것 이다.
이 때문에 변수 a 와 b 는 모두 같은 메모리 위치를 가리키게 된다, 즉 둘다 같은 객체를 가리키게 되는 것이다. 이 때문에 변수 a 에 적용되는 변화나, b 에 적용되는 변화는, 모두 같은 객체에 적용되게 된다.

이러한 자료형의 속성은 함수(Function)으로 아규먼트(Argument)를 넘겨줄 때 두드러지게 되는데

위에서 다룬것 처럼, Primitive Data 는 Value 를 넘겨주게 되고, Object는 Reference, 메모리 주소를 넘겨주게 된다.
그렇기 때문에 아래의 코드와 같은 결과가 나오게 된다.


function test(a, b) {
    a = 44;
    b.name = "name changed to c";
}

var a = 33;
var b = {
    name : "test object"
};

test(a, b);

console.log(a); // 33
console.log(b); // { name: 'name changed to c' }


이 차이를 잘 기억하도록 해, 후에 Argument passing 을 제대로 못해서 잘못된 스크립트를 적는 일이 없도록 하자

댓글 없음:

댓글 쓰기