[TIL] 데이터 타입 심화

·2023년 10월 17일
0

TIL

목록 보기
5/85
post-thumbnail

데이터 타입 심화

데이터 타입의 종류

[기본형과 참조형의 구분 기준]

  • 복제의 방식
    • 기본형 : 값이 담긴 주소값을 바로 복제
    • 참조형 : 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제
  • 불변성의 여부
    • 기본형 : 불변성을 띔
    • 참조형 : 불변성을 띄지 않음
      cf) 불변하다는 것은 데이터 영역 메모리를 변경할 수 없음을 의미

기본형 데이터를 '불변하다'라고 하는 이유

var score;
score = 80;
score = 90;
  • 변수에 값이 재할당되면, 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후, 변수는 새롭게 재할당한 원시 값을 가리킨다. 이때 변수가 참조하던 메모리 공간의 주소가 바뀐다.

참조형 데이터를 '가변하다'라고 하는 이유

// 할당이 이뤄지는 시점에 객체 리터럴이 해석되고, 그 결과 객체가 생성된다.
var person = {
    name: 'Lee'
};

// person 변수에 저장되어 있는 참조 값으로 실제 객체에 접근한다.
console.log(person);  // {name: 'Lee'}

  • 객체는 변경 가능한 값이므로 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다.
// 프로퍼티 값 갱신
person.name = 'Kim';

// 프로퍼티 동적 생성
person.address = 'Seoul';

console.log(person);  // {name: "Kim", address: "Seoul"}

  • 메모리를 효율적으로 사용하기 위해, 객체를 복사해서 생성하는 비용을 절약하여 성능을 향상시키기 위해 객체는 변경 가능한 값으로 설계되어 있다.
  • 객체는 이러한 구조적 단점이 따른 부작용이 있는데, 그것은 여러 개의 식별자가 하나의 객체를 공유할 수 있다는 것이다.

이로 인한 부작용

var person = {
    name: 'Lee'
};

// 참조 값을 복사(얕은 복사)
var copy = person;
  • 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다.
  • 원본 person과 사본 copy는 저장된 메모리주소는 다르지만 동일한 참조 값을 갖는다.
  • 즉, 원본 person과 사본 copy는 동일한 객체를 가리킨다.
  • 따라서 원본 person과 사본 copy 중 어느 한쪽에서 객체의 프로퍼티 값을 변경, 추가, 삭제하면 서로 영향을 주고 받는다.
var person = {
    name: 'Lee'
};

// 참조 값을 복사(얕은 복사), copy와 person은 동일한 참조 값을 갖는다.
var copy = person;

// copy와 person은 동일한 객체를 참조한다.
console.log(copy === person);  // true

// copy를 통해 객체를 변경한다.
copy.name = 'Kim';

// person을 통해 객체를 변경한다.
person.address = 'Seoul;

// copy와 person은 동일한 객체를 가리키기 때문에 서로 영향을 주고받는다.
console.log(person);  // {name: "Kim", address: "Seoul"}
console.log(copy);    // {name: "Kim", address: "Seoul"}

불변 객체

  • 객체의 프로퍼티에 접근해서 값을 변경하면 가변이 성립한다.
// user 객체를 생성
var user = {
	name: 'hyewon',
	gender: 'female',
};
// 객체의 프로퍼티에 접근하여 변경 -> 가변
var changeName = function (user, newName) {
	var newUser = user;
	newUser.name = newName;
	return newUser;
};

var user2 = changeName(user, 'hyetwo');

if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.'); // 출력 X
}

console.log(user.name, user2.name); // hyetwo hyetwo
console.log(user === user2); // true
  • 반면 객체 데이터 자체를 변경하고자 하면 기존 데이터는 변경되지 않는다.
// user 객체를 생성
var user = {
	name: 'hyewon',
	gender: 'female',
};
// 새로운 객체를 반환 -> 불변
var changeName = function (user, newName) {
	return {
		name: newName,
		gender: user.gender,
	};
};

var user2 = changeName(user, 'hyetwo');

if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.'); // 출력 O
}

console.log(user.name, user2.name); // hyeone hyetwo
console.log(user === user2); // false
  • 이 방법이 최선은 아니다.
  • changeName함수는 새로운 객체를 만들기 위해 변경할 필요가 없는 gender프로퍼티를 하드코딩으로 입력했다.
  • 이를 해결하기 위해 얕은 복사의 방법이 있다.

얕은 복사

var copyObject = function (target) {
	var result = {};

	for (var prop in target) {
		result[prop] = target[prop];
	}
	return result;
}

var user = {
	name: 'hyewon',
	gender: 'female',
};

var user2 = copyObject(user); // 1 depth copy (얕은 복사)
user2.name = 'hyetwo';

if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // hyewon hyetwo
console.log(user === user2); // false
  • 얕은 복사 도 여전히 문제가 있다.
  • 객체가 중첩되었을 경우 완벽하게 복사를 할 수 없기 때문이다.
var user = {
	name: 'hyewon',
	urls: {
		portfolio: 'http://github.com/abc',
		blog: 'http://blog.com',
		facebook: 'http://facebook.com/abc',
	}
};

var user2 = copyObject(user);

user2.name = 'hyetwo';

// 바로 아래 단계에 대해서는 불변성을 유지하기 때문에 값이 달라진다.
console.log(user.name === user2.name); // false

// 더 깊은 단계에 대해서는 불변성을 유지하지 못하기 때문에 값이 같다.
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
  • 그러므로 user.urls 프로퍼티도 불변 객체로 만들어야 한다.

깊은 복사

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

var user2 = copyObject(user); // 1 depth copy
user2.urls = copyObject(user.urls); // 2 depth copy

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
  • 중첩된 객체에 또 중첩된 객체가 있다면?
  • 이를 위해 재귀함수를 적용할 필요가 있다.
var copyObjectDeep = function(target) {
	var result = {};
	if (typeof target === 'object' && target !== null) {
		for (var prop in target) {
			result[prop] = copyObjectDeep(target[prop]);
		}
	} else {
		result = target;
	}
	return result;
}
profile
느리더라도 조금씩, 꾸준히

0개의 댓글