오늘은 자바스크립트의 원시 타입 / 참조 타입 / 원시 래퍼 타입을 알아보자.
원시 타입이란 있는 그대로 저장되는 데이터를 표현한다.
아래 예시를 살펴보면 value에 7을 할당하고 콘솔에 찍으면 7이 그대로 표출되는 것을 확인할 수 있다.
var value = "7";
console.log(value); // 출력: 7
원시 타입의 종류로는 아래 5가지가 존재한다.
원시값을 변수에 할당하면 값이 복사되어 들어간다. 즉, 원시값이 할당된 변수들은 모두 자기 자신만의 고유한 값을 가지게 된다.
var one = 1;
var two = 2;
one = two;
one = 3;
console.log(one); // 3
console.log(two); // 2 => two값이 변하지 않는 것을 볼 수 있다.
typeof는 원시값의 종류를 알 수 있게 해주는 메서드이다. null 타입에 주의하자.
console.log(typeof 1); // number
console.log(typeof "hi"); // string
console.log(typeof true); // boolean
console.log(typeof null); // object
console.log(typeof undefined); // undefined
null은 object 타입이기 때문에 만약에 어떠한 값이 null인지 아닌지 확실하게 알기 위해서는 typeof 보단 아래와 같이 ===
연산자를 이용하는게 더 확실하다.
if(value === null) {
// null 이면~
}
참조 타입이란 자바스크립트 객체를 나타낸다.
참조 타입은 변수에 값을 직접 저장하지 않는다.
변수에 저장되는 것은 메모리 안에서 객체의 위치를 가리키는 포인터이다. 무엇이 저장되느냐, 이것이 원시 타입과 참조 타입의 가장 큰 차이점이다.
var objOne = {one: 1};
var objTwo = {two: 2};
objTwo = objOne;
console.log(objTwo); // {one: 1}
objTwo.one = 3; // Q. objOne 의 값은 어떨까?
위 예시에서 objTwo.one에 3이라는 값을 대입했다. 여기서 console.log(objOne);
를 출력하면 어떤 값이 나올까?
console.log(objOne); // {one: 3}
console.log(objTwo); // {one: 3}
바로 {one: 3}
이 출력되는 것을 확인할 수 있다 😨
objTwo를 변경하면 objOne의 값도 동일하게 변경된다. 이 이유는 objTwo에 objOne에 대입되면서 두 객체가 같은 주소를 바라보게 되어서 한 곳에 있는 주소의 값을 이 두 객체가 값을 꺼내서 쓰고 있는 것이다.
만약 공유하고 싶지 않고 싶을때는 어떻게 해야될까? 🤔
바로 Object.assign()
을 사용해보자.
assign 인자로는 복사하고자 하는 target, 복사를 하려고 하는 source 를 전달해주고, 결과로는 target과 source가 통합된 것이 리턴된다.
더 자세한 내용은 MDN 에서 확인해보자.
const objThree = {};
Object.assign(objThree, objOne);
console.log(objThree); // {one: 1}
// 또는 전달하고자 하는 값을 {} 로 해서 작성할 수도 있다.
const objThree = Object.assign({}, objOne);
Object.assign(objThree, objOne); // {one: 1}
하지만 신기하게도 원시 타입도 마치 참조 타입처럼 사용가능하다.
var str = "hello world";
console.log(str.length); // 11
원시타입이지만 마치 객체처럼 메서드를 사용가능하다. 이러한 메서드를 원시 메서드라고 부른다. 이런 원시 메서드를 사용할 수 있는 이유는 원시 래퍼 타입 존재때문이다.
원시 타입을 객체처럼 편리하게 사용하도록 도와준다.
원시 타입을 객체처럼 사용하는 순간, 자바스크립트 내부에서 사용하는 데이터의 인스턴스를 만들게 된다. 이렇게 만들어진 객체는 코드를 실행 후 바로 다음 줄에서 파괴된다. 이러한 과정일 오토박싱 이라고 한다.
var name = "bit";
console.log(name.concat("coin")); // bitcoin concat은 합쳐주는 메서드
위 코드를 자바스크립트는 내부적으로 아래와 같이 처리한다.
var name = "bit";
var temp = new String(name); // 원시 래퍼 타입
console.log(temp.concat("coin")); // concat 메서드 실행 및 temp 임시변수 사용
temp = null; // 바로 다음줄에서 메모리에서 해제
실제 자바스크립트 내부에서는 원시 타입을 객체처럼 사용하는 순간 임시 변수를 만들어서 그 변수의 메서드를 실행하고 바로 해제를 해준다.
여기서 주의해야할 점이 있는데 우선 코드로 확인해보자.
var name = "bit";
name.coin = "coin";
console.log(name.coin); // undefined
앗.. 원시 타입을 마치 객체 타입처럼 쓸 수 있는 것 같아서 name.coin
을 했는데 undefined
가 출력됐다. 값이 할당되지 않았다라는 의미다. 😨
이것도 자바스크립트 내부적으로 풀어서 코드로 알아보자.
// 1번
var name = "bit";
name.coin = "coin";
1번
을 먼저 해석하면 아래 코드처럼 자바스크립트 내부적으로 임시변수를 생성하고 사용한 후 임시변수는 바로 메모리에서 해제가 된다.
// 1번 해석
var name = "bit";
var temp = new String(name); // 임시변수
temp.coin = "coin";
temp = null; // temp는 바로 해제가 된다.
// 2번
console.log(temp.coin);
이어서 2번
을 해석하면 name.coin
원시 타입을 마치 참조 타입처럼 사용하기 때문에 자바스크립트는 temp라는 임시 변수를 생성한다. temp는 이미 1번
에서 할당하고 메모리에서 해제가 되었기 때문에 아무것도 들어있지 않다. 그래서 undefined
가 출력되는것을 확인할 수 있다.
이 때문에 원시 래퍼 타입을 사용할 때는 주의하자. 😤
var temp = new String(name);
console.log(temp.coin); // undefined