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

modi·2023년 10월 19일
0
post-thumbnail

이 글은 코어 자바스크립트를 읽고 학습용으로 요약 및 정리한 글입니다.

데이터 타입의 종류

  1. 기본형: number, string, boolean, null, undefined, (ES6: Symbol)
  2. 참조형: Object, Array, Function, Date, RegExp - 정규 표현식, (ES6: Map, WeakMap, Set, WeakSet)
  • 할당이나 연산: 기본형은 복제, 참조형은 참조
    • 엄밀히 말하자면 둘 다 복제지만, 기본형은 주솟값을 바로 복제하고 참조형은 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제

기본형은 불변성? 그치만 변경할 수 있는데? => 메모리 영역에서 자바스크립트 데이터 처리 과정을 이해해 보자!

데이터 타입에 관한 배경지식

메모리와 데이터

  • 비트: 0 또는 1만 표현할 수 있는 하나의 메몰 조각
  • 각 비트는 고유한 식별자를 통해 위치 확인
  • 비트 단위로 위치를 확인하는 것은 매우 비효율적 => 바이트 단위 탄생
    • 1 바이트 = 8 비트
  • 모든 데이터는 바이트 단위의 식별자, 메모리 주솟값을 통해 서로 구분 및 연결

자바스크립트는 왜 형변환이 자유로울까

  • 정적 타입 언어(C, C++, JAVA): 메모리 낭비 최소화를 위해 데이터 타입별로 할당 메모리 영역을 정해 놓음
  • 자바스크립트는 메모리 용량이 과거보다 커진 상황에 등장 => 메모리 공간을 조금 더 넉넉히 할당 => 형변환 걱정이 덜 발생

식별자와 변수

  • 변수: 변할 수 있는 데이터
    • 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇
  • 식별자: 어떤 데이터를 식별하는 데 사용하는 이름, 변수명

변수 선언과 데이터 할당

var a; // 변수 a 선언
a = 'abc'; // 변수 a에 데이터 할당

var a = 'abc'; // 변수 선언과 할당

변수 영역
@1003: 이름 - a, 값 - @5004

데이터 영역
@5004: 'abc'

  1. 변수 영역에서 빈 공간(@1003) 확보
  2. 확보한 공간의 식별자를 a로 지정
  3. 데이터 영역의 빈 공간 (@5004)에 문자열 'abc' 저장
  4. 변수 영역에서 a라는 식별자 검색 (@1003)
  5. 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입

변수 영역에 값을 직접 대입하지 않고 데이터의 주소를 저장 -> 자유로운 데이터 변환 & 효율적인 메모리 관리 & 높은 중복 데이터 처리 효율

  • 데이터 변경: 기존 데이터(기본형)에 어떠한 변환을 가하든 상관 없이 무조건 새로 만들어 별도의 공간에 저장함

더 이상 기존 데이터가 사용되지 않는 경우에는 어떻게 할까?

  • 참조 카운트: 어떤 데이터에 대해 자신의 주소를 참조하는 변수의 개수
  1. 참조 카운트가 0인 메모리 주소는 가비지 컬렉터(GC)의 수거 대상이 됨
  2. 특정 시점이나 메모리 사용량에 따라 자동으로 수거 대상들을 수거
  3. 수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈 공감이 됨

기본형 데이터와 참조형 데이터

불변값

  • 변수와 상수를 구분하는 성질: 변수 영역 메모리 변경 가능성
    • 한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지
  • 불변성 여부 구분하는 성질: 데이터 영역 메모리 변경 가능성
  • 기본형 데이터인 숫자, 문자, boolean, null, undefined, Symbol 모두 불변값

가변값

  • 참조형 데이터의 기본적 성질은 가변값인 경우가 많지만, 설정에 따라 변경 불가능하거나 아예 불변값으로 활용할 수도 있음
var obj1 = {
  a: 1,
  b: 'bbb'
};

변수 영역
@1002: 이름 - obj1, 값 - @5001

데이터 영역
@5001: @7013 ~ ?
@5003: 1
@5004: 'bbb'

객체 @5001의 변수 영역
@7103: 이름 - a, 값 - @5003
@7104: 이름 -b, 값 - @5004

  • 기본형 데이터와 다르게 객체의 변수(프로퍼티) 영역이 별도로 존재함
  • 객체가 별도로 할애한 영역은 변수 영역일 뿐, 데이터 영역은 기존의 메모리 공간을 그대로 활용 (불변값)
  • 하지만 객체의 내부를 변경하더라도 변수의 값(@5001)은 변하지 않음

변수 복사 비교

  • 가변값인 객체는 참조에 의한 복사 이후 기존 객체의 프로퍼티 값을 바꾸면 복사한 객체의 해당 프로퍼티 값도 변경
    • 기본형은 주솟값을 복사하는 과정이 한 번만 이루어지지만, 참조형은 최소 한 번 더 이루어지기 때문임
  • 기존 객체에 새로운 객체를 할당해 값을 직접 변경하는 경우에는 복사한 객체가 영향을 받지 않음
  • 참조형 데이터가 가변값이라고 설명할 때의 가변은 참조형 데이터 자체가 아닌 그 내부 프로퍼티를 변경할 때만 성립

그래서 객체 복사는 항상 주의해야 한다! 복사한 이후 객체를 변경했다가 기존 객체도 변경되면... 🥲

불변 객체

불변 객체를 만드는 간단한 방법

앞서 말한 것처럼 데이터 자체를 변경하기 (새로운 데이터 할당)

  • 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당
  • 자동으로 새로운 객체를 만드는 도구 활용
  1. 가장 쉬운 방법: 하드코딩
  • 대상 객체에 정보가 많을수록, 변경할 정보가 많을수록 힘들어짐

그렇다면 대상 객체의 프로퍼티 개수에 상관없이 모든 프로퍼티를 복사하는 함수를 만들어둘까?

  1. 얕은 복사
var copyObject = function(target) {
  var result= {};
  for (var prop in target){
    result[prop] = target[prop];
  }
  return result
}
  • 얕은 복사는 바로 아래 단계의 값만 복사함
  • 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사
    • 그러면 또 해당 프로퍼티에 대해 원본과 사본이 모두 동일한 참조형 데이터 주소를 가리키는 문제 발생

이러한 문제를 해결하기 위해서 중첩된 객체의 내부 프로퍼티도 다시 복사해야 한다

  1. 깊은 복사
var copyObjectDeep = function(target){
  var result = {};
  if (typeof target === 'object' && target !== null){
    for (var prop in target){
      result[props] = copyObjectDeep(target[prop]);
    }
  } else {
    result = target;
  }
  return result;
}
  • 재귀적으로 copyObjectDeep 함수를 호출

undefined와 null

자바스크립트 엔진은 사용자가 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로 그렇게 하지 않았을 때 undefined를 반환

  • 값을 대입하지 않은 변수, 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근
  • 객체 내부의 존재하지 않는 프로퍼티에 접근
  • return 문이 없거나 호출되지 않는 함수의 실행
var arr1 = [];
arr1.length = 3;
console.log(arr1); // [empty x 3]

var arr2 = [undefined, undefined, undefined];
console.log(arr2); // [undefined, undefined, undefined]

비어있는 요소와 undefined를 할당한 요소는 다르다

  • 비어있는 요소는 순회와 관련된 많은 배열 메서드들의 순회 대상에서 제외됨 => 배열도 객체다 (아직 존재하지 않는 프로퍼티!)

  • 혼란을 피하기 위해 비어있음을 명시적으로 나타내고 싶을 때는 null을 사용하자

정리

  • 자바스크립트 데이터 타입에는 기본형(불변값)과 참조형(가변값)이 있다
  • 변수: 변경 가능한 데이터가 담길 수 있는 공간
  • 식별자: 변수의 이름
  • 변수를 선언하면 컴퓨터는 메모리 빈 공간에 식별자 저장 -> 그 공간에 자동으로 undefined 할당
  • 변수에 기본형 데이터 할당: 별도의 공간에 데이터 저장하고 그 공간의 주소를 변수의 값 영역에 할당
  • 변수에 참조형 데이터 할당: 내부 프로퍼티들을 위한 변수 영역 별도로 확보 -> 확보된 주소를 변수에 연결 -> 확보한 프로퍼티 변수 영역에 각 프로퍼티의 식별자 저장 -> 각 데이터를 별도에 저장해 그 주소를 식별자들과 매칭
  • 깊은 복사, 라이브러리 등을 활용해 참조형 데이터를 불변값으로 사용할 수 있음
  • undefined: 어떤 변수에 값이 존재하지 않음
  • null: 사용자가 명시적으로 없음을 표현
  • 변수에 실제로 값이 존재하지 않는 경우와 undefined는 다르다! -> null을 사용하자

참고자료

0개의 댓글