코어자바스크립트

[CoreJavaScript] Chatper 01. 데이터 타입 내용 정리

Hyunsangs 2024. 9. 10. 18:16

01 Chapter 데이터 타입

1 - 1 자바스크립트의 데이터 타입 종류


기본형 (Primitive Type)

  • 숫자 (Number)
  • 문자열 (String)
  • 불리언 (boolean)
  • Null
  • undefined
  • ES6 - 심볼(Symbol) 추가

참조형 (Reference Type)

  • 객체 (Object)
    • 배열(Array)
    • 함수 (Function)
    • 날짜( Date)
    • 정규표현식 (RegExp)
    • ES6 - Map, WeakMap, Set, Weakset ( 객체 하위 분류 )

기본형과 참조형을 구분하는 기준?

  • 기본형 : 값이 담긴 주솟값을 바로 복제
  • 참조형 : 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제

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


1- 2-1 메모리와 데이터

비트

  • 0 또는 1만 표한할 수 있는 하나의 메모리 조각
    • 각 비트는 고유한 식별자를 통해 위치 확인 가능
    • 고작 0 이나 1만 표현할 수 있는 비트 단위로 위치 확인하는 것은 매우 비효율적
    • 몇개 씩 묶어 하나의 단위로 여긴다면 표현할 수 있는 값도 늘어 동시에 검색 시간 줄임.
      • 하지만 1바이트로 묶어서하면 검색시간 줄일 수 있지만 낭비되는 비트 발생
    • 1바이트 - 8개의 비트
  • 바이트나 비트의 식별자로 위치 파악 가능
  • 모든 데이터는 바이트 단위의 식별자, 더 정확하게는 **메모리 주소값**을 통해 서로 구분하고 연결

1-2-2 식별자와 변수

변수

  • 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇
  • ‘변할 수 있는 무언가’ 이기에 데이터를 말함.
    • 숫자, 문자열, 객체, 배열 모두 데이터

식별자

  • 어떤 데이터를 식별하는 데 사용하는 이름, 즉 변수명

1-3 변수 선언과 데이터 할당


1-3-1 변수 선언

var a;

 

var a; 명령으로 컴퓨터는 메모리에서 비어있는 공간 확보. 임의로 1003번 지정

이 공간의 식별자을 a라고 지정. 여기까지가 변수 선언 과정

사용자가 a에 접근하고자 하면 컴퓨터는 메모리에서 a라는 이름을 가진 주소를 검색해 해당 공간에 담긴 데이터 반환

1-3-2 데이터 할당

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

var a = 'abc' // 변수 선언과 할당을 한 문장으로 표현
  1. 변수 a를 선언후 a에 데이터 할당하는 방법
  2. 변수 a를 선언과 동시에 할당하는 방법

데이터 할당에 대한 메모리 영역 변화

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

변수 영역에 직접 대입하지 않고 번거롭게 한단계를 거치는 걸까 ❔

→ 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리 효율적으로 관리하기 위한 것.

1 - 4 기본형 데이터와 참조형 데이터


1-4-1 불변값

불변값과 상수 개념❔❔

변수와 상수를 구분 짓는 변경 가능성의 대상 변수 영역 메모리

  • 변수와 상수를 구분하는 성질 ‘변경 가능성’ 이다.
  • 바꿀 수 있으면 변수, 바꿀 수 없으면 상수

불변성 여부를 구분 할 때 변경 가능성의 대상은 데이터 영역 메모리

  • 변경은 새로 만드는 동작으로 통해서만 이뤄지는데, 이것이 바로 불변값 성질
  • cf) 기본형 데이터들은 모두 불변값.

1-4-2 가변값

참조형 데이터의 할당

var obj1 = {
  a: 1,
  b: 'bbb'
};

변경 과정 :

→ 변수 영역 빈공간 (@1002) 확보 주소 이름을 obj1 지정

→ 데이터 저장공간 @5001에 데이터 저장하려고보니 여러 개의 프로퍼티 이뤄진 데이터 그룹이여서 내부의 프로퍼티를 저장하기 위한 별도의 변수 영역 마련 그 영역의 주소 (@7103 ~ ? )를 @5001에 저장

→ @7103 및 @ 7104에 각각 a와 b라는 프로퍼티 이름 저장

→ 데이터 영역에서 숫자 1 검색 없으면 @ 5003 에 저장 그리고 이 주소를 @7103 에 저장 문자열 ‘bbb’ 역시 같은 방법

참조형 데이터의 프로퍼티 재할당

var obj1 = {
	a: 1,
	b: 'bbb'
};
obj1.a = 2;

변경 과정 :

데이터 영역에서 숫자 2 검색 후 없으므로 빈 공간에 저장 → 변수 영역의 주솟값 변경

▶︎ 새로운 객체가 만들어진 것이 아니라 기존의 객체 내부의 값만 변경

중첩된 참조형 데이터(객체)의 프로퍼티 할당

var obj = {
  x: 3,
  arr: [3, 4, 5] 
};

변경 과정:

→ 변수 영역의 빈공간 @1002 확보 주소 이름 obj 지정

→ 임의 데이터 저장 공간 @5001 데이터 저장하려는데, 이 데이터는 여러 개의 변수와 값들을 모아놓은 객체라서 변수들을 저장하기 위해 별도의 변수 영역 마련 @7103 ~ ? , 그 영역의 주소 @ 5001 에 저장

→ 데이터 영역 숫자 3 검색 . 없으므로 임의 @ 5002 저장, 이 주소를 @7103 저장

→ @7104 영역에 배열로서 데이터 그룹. 내부 프로퍼티들을 저장하기 위해 별도 변수 영역 @8104~? 를 @5003 에 저장한 다음, @ 5003 @ 7104에 저장

→ 배열 요소 총 3개이므로 3개 변수 공간 확보 및 각각 인덱스 부여 (0,1,2)

→ 데이터 영역에 숫자 3을 검색해서 @5002 그 주소를 @ 8104에 저장

→ 데이터 영역에 숫자 4 없으므로 @5004에 저장. 이 주소를 @8105에 저장

→ 데이터 영역 숫자 5 없으므로 @5005에 저장. 이 주소를 @8106에 저장

obj.arr = 'str';

// 만약 위의 과정대로 객체를 생성하고 재할당 명령을 내린다면?

중첩된 참조형 데이터(객체)의 프로퍼티 재할당

문자열 재할당 후 사용하지 않는 데이터는 참조 카운트가 0이 된다. 참조 카운트가 0인 메모리 주소는 가비지 컬렉터의 수거 대상이 된다.

가비지 컬렉터는 특정 시점이나 메모리 사용량이 포화 상태에 임박할 때마다 자동으로 수거 대상들을 수거하고, 수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈 공간이 된다.

1-4-3 변수 복사 비교

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

변수 복사

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

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

변수 복사하는 과정에서 기본형 데이터와 참조형 데이터 모두 같은 주소를 봄.

변수 복사 이후 값 변경 결과 비교 (1) - 객체의 프로퍼티 변경 시

b = 15;
obj2.c = 20;

기본형 데이터를 복사한 변수 b는 @1002의 값이 달라 짐.

참조형 데이터를 복사한 변수 obj2의 프로퍼티의 값을 바꾸었더니 @1004 의 값은 달라지지 않음.

코드로 표현 시

a !== b
obj1 === obj2

변수 복사 이후 값 변경 결과 비교 (2) - 객체 자체를 변경했을 때

b = 15;
obj2 = { c: 20, d: 'ddd' }

@1004 의 값이 달라짐.

즉 , 참조형 데이터가 ‘가변값’ 이라고 설명할 때의 ‘가변’은 참조형 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 때만 성립.

1-5 불변 객체

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

기존 불변 객체가 되어야 하는 데이터는 변하지 않고 내부 프로퍼티를 변경할 필요가 있을 때마다

  1. 매번 새로운 객체를 만들어 재할당하기로 규칙을 정한다.
  2. 자동으로 새로운 객체를 만드는 도구를 활용

불변 객체 → 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우 필요 함.

예제 1-12 기존 정보를 복사해서 새로운 객체를 반환하는 함수 ( 얕은 복사 )

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

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

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

if (user1= user2) {
  console.log('유저 정보가 변경돠었습니다.'); // 결과 : 유저 정보가 변경돠었습니다.
}

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

→ user 객체 내부의 변경이 필요할 때는 무조건 copyObject 함수를 사용하기로 합의하고 그 규칙을 지킨다 전제하에서는 user객체가 곧 불변 객체라고 볼 수 있음.

1-5-2 얕은 복사와 깊은 복사

얕은 복사 : 바로 아래 단계의 값만 복사하는 방법

  • 이 말은 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사 할 때 주솟값만 복사 한다는 의미

깊은 복사 : 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법

중첩된 객체에 대한 얕은 복사

var user = {
  name: 'Jaenam',
  urls: {
    portfolio: '<http://github.com/abc>',
    blog: '<http://blog.com/abc>',
    facebook: '<http://facebook.com/abc>'
  }
};
var user2 = copyObject(user);

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

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

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

→ user 객체에 직접 속한 프로퍼티에 대해서는 복사해서 완전히 새로운 데이터가 만들어진 반면, 한 단계 더 들어간 urls 내부 프로퍼티들은 기존 데이터를 그대로 참조

중첩된 객체에 대한 깊은 복사

var user2 = copyObject(user);
user2.urls = copyObject(user.urls);

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

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

→ 객체를 복사할 때 객 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때, 기본형 데이터일 경우에는 그대로 복사하면 되지만 참조형 데이터는 다시 그 내부의 프로퍼티들을 복사해야 함

** 참조형 데이터가 있을 때마다 재귀적으로 함수를 호출하여 객체를 완전히 복사 해야 함.

JSON을 활용한 간단한 깊은 복사 (메서드나 숨겨진 프로퍼티인 __proto__나 getter/setter등과 같이 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);

obj.a = 3;
obj.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]}

1-6 undefined와 null

자바스크립트의 ‘없음을 나타내는 값

두 값의 의미는 같은것 같지만 다르다.

undefined

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

  1. 값을 대입하지 않은 변수, 즉 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
  2. 객체 내부의 존재하지 않 프로퍼티에 접근하려고 할 때
  3. return 문이 없거나 호출되지 않는 함수의 실행 결과

→ 그 자체로 값이 비어있음을 의미

** null 주의 할점

  • typeof null 값은 object 라는거
    • 이유는,,,? 그냥 단순 버그

undefined와 null의 비교

var n = null;
console.log(typeof n); // object

console.log(n == undefined); // ture
console.log(n == null); // ture

console.log(n === undefined); // false
console.log(n === null); // ture

4번째 코드와 같이 동등 연산자(==)로 비교할 경우 null 과 undefined는 서로 같다 판단.

→ 일치연산자를 써야만 null과 undefined를 비교 할 수 있다.