코어 자바스크립트 #1 데이터타입

신윤철·2022년 1월 10일
2

코어자바스크립트

목록 보기
1/8
post-thumbnail

1.데이터 타입의 종류

기본형

  • 숫자 (Number)
  • 문자열 (String)
  • 불리언 (Boolean)
  • Null
  • Undefined

ES6에서 추가

  • 심볼 (Symbol)

참조형

  • 객체 (Object)
  • 배열 (Array)
  • 함수 (Function)
  • 날짜 (Date)
  • 정규표현식 (RegExp)

ES6에서 추가

  • Map
  • WeakMap
  • Set
  • WeakSet

데이터 타입을 나누는 기준?

일반적으로 기본형은 값을 할당하거나 연산할 경우 기본값이 복제되고 참조형은 참조된다고 알려져 있지만 엄밀하게 말하면 틀립니다.
⇒ 둘 모두 복제를 하지만 기본형은 주솟값을 복제하고, 참조형은 값들이 담긴 주솟값을 복제합니다.

시각적으로 간단하게 표현하자면 아래와 같습니다.
값 ⇒ 값의 주소 ⇒ 기본형
값 ⇒ 값의 주소 ⇒ 값의 주소를 갖는 주소 ⇒ 참조형
(잠시 후 아래에서 그림으로 설명하겠습니다.)


2.변수 선언과 기본형 데이터 할당

변수 선언과 메모리 공간

var는 함수 레벨 스코프이기 때문에 실제 업무에서는 절대 사용하면 안되지만 호이스팅, 중복 할당 가능등 개념을 설명 할때 적당하여 사용했습니다.
(chapter1 에선 모든 var를 let으로 사용해도 문제없음)

var a;

위의 코드를 말로 표현하면 '변할 수 있는 데이터를 만들고, 데이터의 식별자를 a로 한다.' 입니다. 처음 선언시 undefine값이 들어있어도 추후에 다른값을 할당할 수 있습니다.
즉, 변수란 변경 가능한 데이터가 담길 수 있는 공간(메모리)입니다.

  • var, let, const의 차이점은 따로 포스팅을 하겠습니다. (여기주소)

변수 선언과 기본형의 값 대입시 메모리 변화를 살펴보겠습니다.

var a;  		// 1. 주소 @101에 식별자 a를 저장하기 위한 메모리를 확보 
a = 'value1';		// 2. 주소 @1022에 문자열 'value1'을 저장 , 3. 주소에서 식별자 a를 검색
			// 4. 주소 @101에 값 'value1'을 저장한 주소 @1022을 값으로 할당
            		(주소는 값으로 할당될 경우 앞에 @로 구분됩니다.)


데이터 타입을 나누는 기준에서 설명한 것처럼 기본형 값을 대입할 경우, 기본형 데이터를 가진 주소(@1022)를 식별자 a를 가진 주소(@101)의 값에 할당합니다.
(주소 @101의 값에 바로 'value1'을 대입하는 것이 아님)

만약 여기서 변수 a에 다른 값을 대입하면 어떻게 되는지 확인해보겠습니다.

var a;			// 1,2,3,4의 과정은 위와 같습니다.
a = 'value1';
a = 'value2';		// 5. 주소 @1023에 문자열 'value2'를 저장합니다.
			// 6. 주소에서 식별자 a를 찾습니다.
            		// 7. 식별자 a의 주소 @101의 값으로 'value2'를 가진 주소 @1023을 저장합니다.


a = 'value2'처럼 새로운 값을 입력할 경우 기존 값인 'value1'을 바꾸는 것이 아닌 새로운 주소에 'value2'을 입력하고 식별자 a의 주소에 값으로 새로운 주소를 입력하며 표출되는 값을 변경합니다.

  • 이처럼 기존 값은 사라지지 않아(불변성) 재사용 될 수 있고, 연결된 주소가 없으면 가비지 컬렉팅되어 자동으로 삭제됩니다.
  • 직접 값을 대입하는 것이 아닌 값의 주소를 대입하므로써 데이터 변환을 자유롭게 하고, 메모리를 더 효율적으로 사용할 수 있습니다.

※이처럼 값을 입력받을때 직접 입력받는 것이 아닌 값을 가진 주소를 입력받는 이유.

위에서 말한 것 처럼 메모리를 자유롭게 이용하며, 효율적으로 사용하기 위해서입니다.

자바스크립트는 숫자형 데이터에는 8byte의 공간을 확보하지만 문자열은 특별할 규격없이 가변적인 메모리용량을 확보합니다.

그런데 만약 위처럼 주소에 직접 값을 저장할 경우, data2 처럼 메모리 중간에 큰 값이 재할당되면 해당 주소의 메모리용량을 늘린만큼 그 뒤에 이어지는 주소들도 모두 그만큼 뒤로 옮기고 다시 저장해야하는 작업을 거쳐야합니다. (매우 비효율적)

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

불변값

변수와 상수를 구분하는 성질은 '변경 가능성'입니다. 변수는 변경 가능한 반면 상수는 변경 불가능합니다.
이때문에 불변값과 상수를 같은 개념으로 생각할 수 있는데 이 둘은 큰 차이가 있습니다.

  • 상수 : 주소에 한번 데이터 할당이 일어나면 다시 다른 주소값으로 변경할 수 없다는 점을 기준으로 변경 불가능을 정의합니다.
  • 불변값 : 변수에 새로운 값을 입력하기위해 주소값을 변경해도 기존에 존재하는 데이터는 사라지지 않고 메모리상에 데이터로 존재합니다. (가비지 컬렉팅 당하지 않는한 계속 존재)

가변값

기본형 데이터는 모두 불변값입니다. 그렇다면 참조형 데이터는 모두 가변값일까요?
기본적인 성질은 가변값인 경우가 많지만 사용자의 설정에 따라 별경 불가능한 경우도 있고 불변값으로 활용하는 방법도 있습니다.

4.변수 선언과 참조형 데이터 할당

변수 선언과 참조형 데이터의 값 대입시 메모리의 변화를 살펴보겠습니다.

var obj1 = {		//1. 컴퓨터는 빈 공간(@101)을 확보하고 식별자명을 obj1로 지정합니다.
	a: 1,		//2. 식별자 obj1의 내부 프로퍼티를 저장할 별도의 영역을 마련하고, 그 영역의 주소를 @1020에 저장합니다. 
    	b: 'yun'	//3. @2001, @2002에 각각 a와 b라는 프로퍼티 명을 지정합니다.
};			//4. 메모리에서 a의 값인 1과 b의 값인 'yun'을 검색하고, 
			//5. 없으면 새로운 주소 @1022, @1023에 1과 'yun'을 할당하고 @2001, @2002의 값으로 주소값을 줍니다. 


① 식별자 obj1의 값으로 내부프로퍼티의 주소를 담은 주소 @1020을 저장합니다.
② 내부프로퍼티의 값들을 저장할 별도의 영역을 마련하고(가변), 내부프로퍼티 명을 지정한 뒤 프로퍼티 주소를 @1020의 값으로 저장합니다.
③ 내부프로퍼티에 할당된 값을 메모리상에서 검색하고 없으면 해당 값을 저장할 공간을 마련하고 1과 'yun'을 저장한 뒤 주소를 프로퍼티의 값으로 할당합니다.

  • 참조형 데이터와 기본형 데이터의 차이는 객체의 변수(프로퍼티)를 담는 메모리 영역이 별도로 존재한다는 것 입니다.

만약 여기서 객체의 프로퍼티를 변경하면 어떻게 되는지 살펴보겠습니다.

var obj1 = {		//1,2,3,4,5의 과정은 위와 같습니다.
    a: 1,		 
    b:'yun'		//6. 메모리의 주소 @1024에 새롭게 추가된 값 10을 넣을 공간을 확보합니다.
    			//7. 식별자 a의 주소 @2001에서 메모리상에서 10을 찾아 그 주소를 값으로 받습니다.
}
obj1.a = 10
obj1.c = 1


참조형 데이터에서 프로퍼티의 값을 재할당하면 그림과 같이 객체에 연결된 메모리가 아닌 객체의 프로퍼티에 연결된 메모리에서 변화가 일어납니다.
메모리 내부에서의 동작이 이런 차이가 있기 때문에 변수의 복사에서 기본형과 참조형데이터 사이의 차이가 생깁니다.

5.기본형과 참조형의 변수 복사 비교

기본형 데이터의 변수 복사

먼저 기본형 데이터에서 변수를 복사하면 어떻게 되는지 살펴보겠습니다.

  • b = a로 a를 복사하여 b에 대입하면, 메모리상에서 새로운 주소에 식별자 b를 저장하고 식별자 a와 같은 주소를 값으로 갖으므로써 같은 값을 저장하게 됩니다.
  • 그리고 만약 복사한 b에 새로운 값을 할당하면 메모리 상에서 할당된 값 200이 있는지 확인하고 없으면 200을 담을 메모리 공간을 만들고 @1002주소에 200을 할당합니다.
  • 이 과정을 마치면 식별자 a와 식별자 b는 서로 다른 주소값을 갖게되고 즉, 서로 다른 값을 갖게 됩니다.

참조형 데이터의 변수 복사

다음으로 참조형 데이터에서 변수를 복사하는 과정을 살펴보겠습니다.

  • obj2.a = 20; 코드를 통해 복사한 obj2 객체의 프로퍼티값을 잘 변경했고 메모리상에서도 잘 변경된 것을 확인할 수 있습니다.
  • 하지만 obj1의 값을 출력해보면 변경한 것은 obj2의 프로퍼티인데, obj1의 프로퍼티값까지 변경된 것을 확인하실 수 있으실겁니다.
  • 그 이유는 그림처럼 객체 obj1, obj2의 값이 여전히 같은 주소를 가리키고 있기 때문입니다.
    여기서 참조형과 기본형의 변수 복사에서 큰 차이가 생기게 됩니다.
  • 때문에 내부 프로퍼티를 변경하면 원본데이터도 변화될 수 밖에 없고, 이 때문에 참조형 데이터는 가변성이 있다고 볼 수 있습니다.

그렇다면 참조형 데이터는 복사를 할 경우 원본데이터를 변하지 않게 할 순 없을까요?
참조형 데이터에 불변성을 넣는 방법은 객체를 복사한 뒤 새로운 객체를 할당하는 것 입니다.

참조형 데이터의 변수를 복사하고 새로운 객체를 할당하는 방법을 살펴보겠습니다.

  • 객체 obj1을 생성하고 obj2를 복사할때까지는 두 객체 obj1, obj2는 같은 주소 @1000를 가리키고 있습니다.
  • 하지만 obj2에 새로운 객체를 할당하는 순간 식별자 obj2의 값에는 새로운 객체의 프로퍼티를 담은 주소값을 갖는 @1003이 저장됩니다.
  • 그 다음의 과정은 참조형 데이터의 메모리 할당과정과 같게 진행되게 됩니다.

여기서 중요한 점은 참조형 데이터를 복사했음에도 객체 obj1 과 obj2의 값이 서로 달라졌다는 점입니다.
때문에 복사된 객체 obj2의 프로퍼티를 변경해도 원본데이터에는 영향을 줄 수 없습니다.

이렇게 참조형 데이터를 불변화 시키는, 즉 불변 객체를 만드는 방법은 자주 쓰이니 잘 알아둬야합니다.
얕은 복사, 깊은 복사(불변객체 만들기)

6.undefined와 null

자바스크립트에서는 비어있다는 표현을 나타내는 방법이 두가지 있습니다.

  • undefined, null

그렇다면 이 둘의 차이는 무엇일까요?
이 둘은 사용 목적도 발생 원인도 다르니 알아둬야합니다.

undefined은 두가지 방법으로 부여될 수 있습니다.

  • 사용자가 직접 정의할 경우 (보통 이렇게 사용하지 않음)
  • 값이 존재하지 않아 자바스크립트 엔진이 자동 부여하는 경우
      1. 식별자만 정의하고 연결된 주소값을 지정하지 않았을 때 ( ex. let a; )
      1. 객체 내부의 존재하지 않는 프로퍼티에 접근할 때
      1. return 문이 없거나 호출되지 않는 함수의 실행 결과를 사용할 때
//1 
var a;
console.log(a);         //undefined
//2
var obj = {a : 1};
console.log(obj.a);     //1
console.log(obj.b);     //undefined
//3
var func = function(){};
var c = func();
console.log(c);         //undefined

그런데 배열을 사용할때 값을 할당하지 않으면 문제가 생깁니다.

var arr1 = [];
arr1.length = 3;
console.log(arr1); 		//[empty * 3]

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

앞서 배운것처럼 배열을 생성하고 크기만큼 값을 주지 않으면 자바스크립트 엔진에서 undefined를 자동 부여할 것 같지만, 실상은 empty를 출력합니다.
        (※ 기본형과 배열의 메모리상에서의 차이)

  • empty는 말그대로 빈값으로 undefined, null과 다르게 문자 그대로 빈값이 됩니다.
    (null, undefined는 비어있다는 의미가 들어있는것... 이해가 잘 되지 않을 수 있지만 정말로 빈값비어있다는 의미가 있는 값과 차이를 생각해 주시면 됩니다.)

이렇게 empty가 할당된 array는 순회와 관련된(forEach, map, filter..) 배열 메서드들의 순회 대상에서 제외됩니다. (없는값으로 취급하여 무시됨)

그렇다면 undefined가 있는데 굳이 null이 존재하는 이유는 무엇일까요?
null은 한가지 방법으로만 사용될 수 있습니다.

  • 바로 사용자가 비어있음을 명시적으로 나타내고 싶을 때, 사용자에 의해서만 쓰일 수 있게 됩니다.

따라서 헷갈리지 않도록 '비어있음'을 명시적으로 나타내고 싶을때엔 null을 값을 대입하지 않은 변수에 접근하게 될때엔 자바스크립트 엔진이 반환해주는 undefined을 받도록 하면 됩니다.

※ null을 사용할때 주의할 점이 있습니다.

  • 바로 typeof null을 object로 인식하는 자바스크립트 자체 버그입니다.
    때문에 변수의 값이 null인지 판단하기 위해선 typeof 대신 console.log등 다른방법을 사용해야합니다.
profile
기본을 탄탄하게🌳

0개의 댓글