[코어 자바스크립트] 데이터 타입

Jimi Choi·2023년 3월 29일
0
post-thumbnail
post-custom-banner

데이터 타입

기본형 (Primitive Type)

  • Number
  • String
  • Boolean
  • null
  • undefined
  • Symbol (ES6에서 추가됨)

→ 일반적으로 불변값

참조형 (Reference Type)

  • Object
    • Array
    • Function
    • RegExp (정규 표현식)
    • Set / WeakSet (ES6)
    • Map / WeakMap (ES6)

→ 일반적으로 가변값


자바스크립트 메모리 구조

  • 스택 메모리 영역
    • 변수
    • 기본형 데이터
    • 정적 할당
  • 힙 메모리 영역
    • 참조형 데이터
    • 동적 할당


데이터 할당

  • 데이터 할당 시 변수 영역에 빈 공간 확보 후(선언) 데이터 영역에 데이터 저장 (할당)
    • 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 효율적으로 관리할 수 있음
  • 변수는 변경 가능한 데이터가 담길 수 있는 공간이고, 식별자는 그 변수의 이름

1. 기본형에서 데이터 바꾸는 경우

  • 문자열 공간을 새로 만들어서 저장하고 해당 주소를 변수 공간에 연결
  • 기본형은 불변값

2. 참조형에서 데이터 바꾸는 경우

  • 한 단계를 더 거침 (객체의 변수 영역이 별도로 존재함)
  • 데이터 영역에 프로퍼티를 저장하기 위한 별도의 객체 변수 영역 주소를 저장하고 후 데이터 영역에다 객체 프로퍼티 저장
  • 데이터영역은 불변값이지만 변수 영역은 가변값이므로 참조형 데이터는 가변값이다

참조 카운터가 0인 경우 GC에 의해 사라질 예정



값을 저장하는 방식

  1. 값을 직접 저장
    • 데이터 할당 시에는 빠름
    • 비교하는데 비용이 많이 듦
    • 메모리 낭비가 심함
  2. 값의 주소를 저장
    • 데이터 할당시에는 느림
    • 비교에 비용이 들지 않음
      • 같은 값이 오직 하나만 존재함 (불변값)
    • 메모리 낭비 최소화

변수를 복사하는 과정

  • 기본형 데이터와 참조형 데이터 모두 같은 주소를 바라보게 됨

변수 복사 이후 값 변경

  • 기본형 데이터는 변수 영역의 주솟값이 변경됨
  • 참조형 데이터는 별도의 객체 변수 영역에 해당하는 주솟값이 변경되므로 변수 영역 주솟값은 동일함

(1) 객체의 프로퍼티 변경

var a = 10;
var b = a;
var obj1 = { c: 10, d: 'ddd'};
var obj2 = obj1;

b = 15;        // a != b
obj2.c = 20;   // obj1 === obj2
  • 다른 값을 대입해도 주솟값이 변하지 않기 때문에 가변값인 상황
  • 기본형도 결국 주솟값을 복사한다.
    • 다만 기본형은 주솟값을 복사하는 과정이 한 번만 이루어지고, 참조형은 한 단계 더 거침

(2) 객체 자체를 변경

var a = 10;
var b = a;
var obj1 = { c: 10, d: 'ddd'};
var obj2 = obj1;

b = 15;
obj2 = { c: 20, d: 'ddd' }; 
  • 메모리의 데이터 영역의 새로운 공간에 새 객체가 저장되고 그 주소를 obj2에 위치 ⇒ 주솟값이 달라짐
  • 따라서 참조형 데이터가 가변값이라고 설명할때의 “가변”은 참조형 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 때만 성립


불변 객체

  • 데이터 자체를 변경하고자 하면 기존 데이터는 변하지 않음
  • 불변성을 확보할 필요가 있는 경우는 언제일까?
    • 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우
      → Ex) 정보가 바뀐 시점에 알림을 보내야 한다거나, 바뀌기 전 정보와 바뀐 후 정보의 차이를 보여줘야하는 경우 등

(1) 변경 전 - 가변성에 따른 문제점

var user = {
	name: 'Jimi',
	gender: 'male'
};

var changeName = function (user, newName) {
	var newUser = user;
	newUser.name = newName;
	return newUser;
}

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

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

console.log(user.name, user2.name); // Jung Jung
console.log(user === user2);        // true

(2) 변경 후 - 기존 정보를 복사해서 새로운 객체를 반환하는 함수 (얕은 복사)

var copyObject = function (target) {
	var result = {};
	for (var prop in target) {
		result[prop] = target[prop];
	}
	return result;
};
var user = {
	name: 'Jimi',
	gender: 'male'
};

var user2 = copyObject(user);
user2.name = 'Jung';

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

console.log(user.name, user2.name); // Jimi Jung
console.log(user === user2);        // false

→ copyObject 함수를 사용하기로 합의하고 규칙을 지킨다는 전제 하에 user 객체는 불변 객체


얕은 복사와 깊은 복사

  1. 얕은 복사

    • 바로 아래 단계의 값만 복사하는 방법
    • 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사함
      • 한 단계 더 들어간 내부 프로퍼티들은 기존 데이터를 그대로 참조함
    • 사본을 바꾸면 원본도 바뀌고, 원본을 바꾸면 사본도 바뀜

  2. 깊은 복사

    • 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법
    • 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우 그대로 복사하면 되지만, 참조형 데이터는 다시 그 내부의 프로퍼티들을 복사해야함

    (1) 객체의 깊은 복사를 수행하는 범용 함수

    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;
    }

    → 원본과 사본이 서로 완전 다른 객체를 참조하게 되어 어느 쪽 프로퍼티를 변경하더라도 영향을 주지 않음


    (2) JSON을 활용한 간단한 깊은 복사

    var copyObjectViaJSON = function (target) { //
    	return JSON.parse(JSON.stringify(target));
    };
    
    var obj = {
    	a: 1,
    	b: {
    		c: null,
    		d: [1, 2],
    		func1: function() { console.log(3); }
    	},
    	func2: function() { console.log(4));
    };
    
    var obj2 = copyObjectViaJSON(obj);
    
    obj2.a = 3;
    obj2.b.c = 4;
    obj.b.d[1] = 3;
    
    console.log(obj); // { a: 1, b: {c: null, d: [1,3], func1: f()}, func2: f() }
    console.log(obj2); // { a: 3, b: {c: 4, d: [1, 2] } }


undefined와 null

1. undefined

  • 사용자가 명시적으로 지정할 수도 있지만 ‘값이 존재하지 않을 때’ 자바스크립트 엔진이 자동으로 부여하는 경우도 있음

  • 자바스크립트 엔진이 부여하는 경우
    (1) 값을 대입하지 않은 변수에 접근할 때
    (2) 객체 내부의 존재하지 않는 프로퍼티에 접근하려고 할 때
    (3) return 문이 없거나 호출되지 않는 함수의 실행 결과

    → (1)에서 값을 대입하지 않은 배열의 경우는 empty가 출력됨.

배열은 객체이기 때문에 값이 지정되지 않은(존재하지 않는) 프로퍼티에 대해선 순회할 수 없음

  • undefined 의미 구분
    1. 사용자가 명시적으로 부여한 경우
      • 비어있음을 의미하긴 하지만 하나의 값으로 동작함 [실존하는 데이터]
    2. 비어있는 요소에 접근할 시 자바스크립트 엔진이 반환한 경우
      • 해당 프로퍼티 내지 배열의 키값 자체가 존재하지 않음 [값이 없음]

❗ ES6의 let, const에 대해서는 undefined를 할당하지 않은 채로 초기화를 마치며, 이후 실제 변수가 평가되기 전까지는 해당 변수에 접근할 수 없음

2. null

  • ‘비어있음’을 명시적으로 나타내고 싶을 때 undefined 대신 사용하기
  • == 동등 연산자로 비교할 경우 null, undefined가 같다고 판단함
  • typeof null이 object라는 버그가 있음
    === 일치 연산자를 써야만 정확히 판별
post-custom-banner

0개의 댓글