[TIL] JavaScript - 데이터 타입

이현동·2023년 1월 21일
0

TIL

목록 보기
12/59

데이터 타입

변수와 식별자의 차이

  • 변수 : 변할 수 있는 수, 데이터가 변할 수 있는 무언가, 무언가는 데이터를 말함
  • 식별자 : 데이터를 식별하기위해 사용되는 이름, 변수명을 말함

자바스크립트에서 기본형과 참조형

기본형 : Number, String, Boolean, Null ...
참조형 : Array, Function, Date, RegExp...

기본형 데이터와 참조형 데이터는 변수를 할당하는 과정에서 차이가 발생합니다.

  • 기본형은 변수 영역에서 식별자를 할당 → 데이터 영역에 값을 할당 → 데이터 영역에 할당한 값의 주소를 식별자에 준다.

  • 참조형은 변수 영역에서 식별자를 할당 → 객체의 변수(프로퍼티) 영역을 따로 할당하고 그 주소를 식별자에 할당 → 값을 객체의 변수(프로퍼티)영역에 식별자를 할당 → 데이터 영역에 값을 할당하고 그 주소를 객체의 변수 영역에 있는 식별자에 할당

구분 기준

1. 복제의 방식

기본형은 값이 담긴 주소값을 바로 복제하게 됩니다. 하지만 참조형은 값이 담긴 주소값(기본형)의 묶음을 가리키는 주소값을 복제하게 됩니다.

2. 불변의 여부

데이터 영역에서 할당된 값이 바뀌냐, 바뀌지 않느냐의 차이입니다.
기본형은 불변인데, 변수 영역에서 데이터가 바뀌는 것이 아니라 데이터 영역에서 값이 새로 할당되고 변수 영역에서 데이터의 주소값이 바뀌기 때문에 불변 입니다.
하지만 참조형은 예를 들어, 객체를 선언했을 때, 객체 변수(프로퍼티) 영역이 별도로 존재하게 됩니다. 이로 인해 참조형에서 복사하고 복사본의 값을 변경하게되면 원본까지 값이 바뀌는 현상이 발생합니다.

//기본형 데이터
var a = 10;
var b = a;

//참조형 데이터
var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;

// 데이터 영역에서 값이 새로 할당되면서 a는 10으로 바뀌지 않음
b = 15; 

// obj1.c의 값도 20으로 바뀌게 됨
obj2.c = 20;

console.log(obj1.c === obj2.c); // true

불변 객체

위의 코드에서와 같이 참조형이 가변인 이유로 쉽게 얘기해서 원본의 객체의 값까지 바뀌게 되는 현상이 발생합니다. 원본객체와 복사된 객체가 서로 같은 주소를 참조하지 않는 불변객체가 필요하게 됩니다. 방법은 원본과 복사본이 같은 객체의 변수 영역 주소를 사용하지 않아야 합니다.

얕은 복사와 깊은 복사

중첩 객체일 떄, 내부 객체의 주소도 같이 복사가 됩니다. 따라서 객체를 복사할 때, 내부 객체의 주소 또한 새로 할당이 되어야 합니다. 그렇지 않으면 복사된 내부 객체가 같은 주소를 사용하기 때문에 두 개 다 같은 값으로 변경됩니다.
깊은 복사를 위해서는 내부 객체의 주소 또한 새로 할당을 해야합니다.

위의 코드에서 obj1.c를 바꾸지 않기 위해서는 얕은 복사를 통해 해결할 수 있습니다.


var a = 10;
var b = a;

//참조형 데이터
var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;

// 데이터 영역에서 값이 새로 할당되면서 a는 10으로 바뀌지 않음
b = 15; 

// obj1.c의 값도 20으로 바뀌게 됨
obj2 = {c: 20, d: 'ddd'}; // 객체 자체를 새로 할당해 값을 변경했기 때문에 obj2가 obj1과 같은 참조값을 가지지 않음.

console.log(obj1.c === obj2.c); // false

하지만 위 방법(얕은 복사)은 아래와 같은 중첩 객체가 있는 경우에는 내부 객체의 주소는 새로 할당을 하지 않습니다.

var copyObject = function (target) {
	var result = {};
	for (var prop in target) {
		result[prop] = target[prop];
	}
	return result; // 객체 자체를 새로 할당 후 return
}

var user = {
	name: 'hdlee',
	urls: {
		portfolio: 'http://github.com/abc',
		blog: 'http://blog.com',
		facebook: 'http://facebook.com/abc',
	}
};

var user2 = copyObject(user); // user.url에 객체의 프로퍼티 영역의 주소와 user.url의 주소가 같음

user2.name = 'brother';
console.log(user.name === user2.name); // flase

user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // true

user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true

위 코드의 문제를 해결하기 위해 깊은복사가 필요합니다.

var copyObjectDeep = function(target) {
	var result = {};
	if (typeof target === 'object' && target !== null) {
		for (var prop in target) {
			result[pop] = copyObjectDeep(target[prop]); // 내부 객체또한 새로운 조소로 할당
		}
	} else {
		result = target;
	}
	return result;
}

var user2 = copyObjectDeep(user);

user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // false

user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // false

참고자료

코어자바스크립트, 정재남 지음

profile
https://hdlee.dev

0개의 댓글