[Javascript] Javascript의 객체, Box과 Unboxing 그리고 First Class Object

Javascript 객체의 Boxing과 Unboxing

Javascript에는 모두가 잘 알다시피 데이터의 타입은 총 6가지이며, 그 원시 데이터(primitives) 타입이 총 5가지가 존재한다.

  • Undefined
  • Null
  • Boolean
  • String
  • Number

이 중에서 Number, String, Boolean 이 3가지만이 원시 데이터 타입 래퍼( primitive wrapper) 를 가진다. Boxing과 Unboxing은 이 원시 데이터 타입 래퍼의 다룰 수 있는 방법이다. 여기에서의 Boxing과 Unboxing에 대한 자료를 검색해보면 모든 예제는 Java로만 나와 처음에는 Javascript에는 해당되지 않는 개념인지 알았다. 하지만 그 개념을 보면 결국에는 평소에 얘기하는 ‘Call by Reference’와 ‘Call by Value’ 와도 밀접한 관계가 있다.

let string1 = 'Hello World';
let string2 = new String('Hello World');

위에서의 예제에서 보면 string1과 string2에 각각 ‘Hello World’ 라는 문자열을 가진 string을 선언했다. 사실 이전에는 위의 두 선언법에 대해 단순히 String 인스턴스를 이용해서 만들어주냐, 아니면 바로 값을 대입해주냐 정도로만 알고 사용했었다. 하지만 2가지를 비교해보면 둘은 엄연히 다르다.

let string1 = 'Hello World';
let string2 = new String('Hello World');

console.log(typeof string1);    //result: string
console.log(typeof string2);    //result: object

console.log(string1 == string2);    //result: true
console.log(string1 === string2);    //result: false

일단 먼저 string1의 type은 ‘string’ 이며, string2의 type은 ‘object’ 이다. Javascript 특성상 비교연산자를 이용하면 자동 형변환으로 인해 두 변수는 같다고 나오지만, 일치 연산자에서는 다르다고 나온다. 그렇다라는 것은 string1 변수는 그 자체의 값이 담겨있지만(call by value), string2는 그 값이 할당된 주소를 참조(call by reference)하고 있다는 것이 된다.

여기에서 Boxing과 Unboxing에 대한 개념과 연관지어보면, string2와 같은 변수를 Boxing 된 변수라고 할 수 있다. Boxing이란 말 그대로 포장, Unboxing은 포장을 푸는 것이라는 의미로 Boxing은 원시 데이터 타입을 Boxing하여, 참조형으로 만들어 주는 것이며 Unboxing은 반대로 참조형 변수를 원시 데이터 타입으로 만들어주는 것을 의미한다.

위의 예제를 다시 살펴보면 string2와 같이 boxing된 변수의 경우에는 string1과 다르게 새로운 값을 대입할 수 있다.

let string1 = 'Hello World';
let string2 = new String('Hello World');

console.log(typeof string1);    //result: string
console.log(typeof string2);    //result: object

console.log(string1 == string2);    //result: true
console.log(string1 === string2);    //result: false

string1.newString = 'Hello there';
string2.newString = 'Hello there';

console.log(string1);   //result: 'Hello World'
console.log(string2);   //result: String {"Hello World", newString: "Hello there"}

console.log(string1 == string2);    //result: true
console.log(string1 === string2);    //result: false

위와 같이 새로운 값이 할당된다. 위의 예제에서 한가지 이해 안되었던 것은 string1 과 string2은 값 자체가 다른데, 비교 연산자를 이용하면 true값을 반환한다. 이 것은 string2의 구조를 보면 알 수 있다.

console.dir(string2);

/* result
String: 
 0: "H"
 1: "e"
 2: "l"
 3: "l"
 4: "o"
 5: " "
 6: "W"
 7: "o"
 8: "r"
 9: "l"
 10: "d"
 newString: "Hello there"
 length: 11
 __proto__: String
 [[PrimitiveValue]]: "Hello World"
*/

위에서 보면 [[PrimitiveValue]] 프로퍼티가 있다. ecma 표준을 찾아본 결과, 하나의 내부 변환 알고리즘이라고 한다. 이 프로퍼티의 value 덕에 string1과 string2가 서로 일치하는 하는 것처럼 보인다.

Javascript의 First Class Object

컴퓨터 프로그래밍 언어에서 특정 언어의 일급 객체는 일반적으로 다른 객체들에 적용 가능한 연산을 모두 지원하는 객체를 가르킨다. 여기에서의 연산이란 함수에 매개 변수 넘기기, 변수에 대입하기와 같은 연산을 말한다. 1급 객체의 조건은 아래와 같다.

  • 변수나 데이터 구조 안에 담을 수 있다.
  • 파라미터로 전달 할 수 있다.
  • 반환값으로 사용할 수 있다.
  • 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.
  • 동적으로 프로퍼티 할당이 가능하다.

1급 함수는 다른 말로 1급 시민(First Class Citizen)이라는 말로도 사용한다.

일단 Javascript에서의 function은 Function 의 객체로서 말 그대로 객체로 취급된다. MDN에 따르면 Javascript에서, 함수는 다른 객체처럼 속성 및 메서드를 가질 수 있기에 1급 객체 라고 정의하고 있다.

1. 변수에 담을 수 있다.

아래와 같은 형태의 함수 선언을 함수 리터럴 이라고 한다. 리터럴이란 코드상에서 데이터를 표현하는 방식으로 이러한 함수 리터럴의 특징은 식별자와 값을 가진 형태로 마치 변수 선언과 같은 형태로 생성되고 있다. 이러한 리터럴 표기법은 JSON에도 영감을 주었다고 한다.

var obj = function () {}

2. 파라미터로 전달 할 수 있다.

Promise 패턴이나 asnyc 등이 추가되기 전이나 babel이 붙어 있지 않아, ECMA script 를 이용하기 힘들 때 등등 이러한 경우에 비동기에 대한 처리를 콜백함수를 이용해서 많이 한 것 같다. 이 뿐만이 아니더라도 callback 함수를 쓰는 경우는 많이 있는 데 그 때마다 파라미터로 함수를 전달한다.

function callback ( a, b ) {
	return a + b;
}
function bindData(func) {
	var num1 = 3;
    var num2 = 7;
    
    var result = func(num1, num2);
    alert( result );
}

bindData( callback );

3. 반환값으로 사용할 수 있다.

함수에서의 반환값은 함수 자체가 값으로 취급되기 된다. 간단한 계산기를 만드는 경우를 그 예로 들 수 있다.

function addition (a, b) {
	return a + b;
}

function multiplication (a, b) {
	return a * b;
} 

function subtraction(a, b) {
	return a - b;
}

function division(a, b) {
	return a/b;
}

var result1 = addition(1, 2);
var result2 = multiplication(3, 3);
var result3 = subtraction(10, 7);
var result4 = division(4, 2);

console.log(result1);
console.log(result2);
console.log(result3);
console.log(result4);

4. 동적으로 프로퍼티 할당이 가능하다.

Javascript에서 함수는 객체로 취급된다. 그러므로 프로퍼티 역시 자유롭게 할당할 수 있다.

function calculator () {
  console.log('계산기 실행');
}

calculator.addition = function (a, b) {
	return a + b;
}

calculator.getResult = function (result) {
	console.log(result);
}

calculator.getResult( calculator.addition(1,2) ); //result: 3

출처

Comments