JavaScript(2) - Primitive( 기본형 ) VS Reference( 참조형 )

용스·2022년 5월 20일
0

JavaScript

목록 보기
2/5

Primitive? Reference?

JavaScript는 크게 두가지 자료형으로 나눌 수 있다.

1. JavaScript의 자료형

JavaScript의 어떤 자료형이 있는지 한번 정리하고 지나가야겠다.

/* Primitive Type*/
let val1;						//  undefined type
let val2 = null;				//  Null type
let val3 = 10;					//	Number type
let val4 = 'test';				//	String type
let val5 = true;				//	boolean type
let val6 = Symbol();			//	Symbol type
let val7 = 9007199254740991n;	//  BigInt type
/* Reference Type */
let val = [1, 2, 3];		// Array
let val2 = {				// Object
  firstname: 'gom',
  lastname: 'ji',
}
class val3 = {
  firstname: 'gom',			// class
  lastname: 'ji',
}
function test(){
  console.log("test");		// function
}

Primitive Type( 원시 타입 )

  1. undefine(할당되지 않은)
  2. null( 값이 없는 )
  3. Number( 숫자형 )
  4. String( 문자 or 문자열 )
  5. Boolean( true or false )
  6. Symbol
  7. BigInt

객체가 아닌 데이터 유형을 말한다.
메모리상에 고정된 크기로 저장되며 원시 데이터를 보관한다. 그렇기 때문에 한번 만든 값을 바꿀 수 없는 불변성을 가진다.

let a = 100;
// a는 Pirimitive type이기 때문에 메모리 주소값을 할당 받는다.
a = 200;
// 메모리에서 200이라는 데이터를 찾고, 없으면 새로운 메모리 공간을 할당하여 200을 저장 후, 그 주소를 a에 저장한다.

Reference Type

  1. Array
  2. Object
  3. Class
  4. function
  5. RegExp( 정규 표현식 )
  6. Map
  7. Set

참조 타입은 변수에 할당할때 값이 아닌 데이터의 주소를 저장한다.
여기서 데이터 주소라는 점을 기억하자.

다음 코드를 보며 비교해보자.

/* Primitive Type */
let value = 3;
let value2;
value2 = value;

console.log( value );
// 출력결과 : 3
console.log( value2 );
// 출력결과 : 3

value2 = 4;
console.log( value );
// 출력결과 : 3
console.log( value2 );
// 출력결과 : 4

Primitive type의 경우, 독립적인 메모리에 원시 데이터를 그대로 저장하기 때문에 값을 변경해도 한꺼번에 변경되지 않는다.
그림으로 표현하면 다음과 같다.

변수를 선언하면 각각의 공간을 가지게 되고 value2 = value을 통해 value의 값을 복사해온다.
변수마다 각각의 공간에 고유의 값을 가지게 되므로, value2의 값을 변경해도 value의 값은 변경되지 않는다.

그럼 Reference Type은 어떨까

let obj = {
  name: 'jigom',
  age : 35
}

let obj2 = obj;

console.log( obj );
// 출력 결과 : { name: 'jigom', age: 35 }
console.log( obj2 );
// 출력 결과 : { name: 'jigom', age: 35 }

Primitive Type처럼 객체 obj를 obj2에 복사하고 값을 변경해보았다.

obj2.name = 'Tom';
// obj의 name은 'jigom' obj2 의 name은 'Tom'이겠지?
console.log( obj );
// 출력 결과 : { name: 'Tom', age: 35 }
console.log( obj2 );
// 출력 결과 : { name: 'Tom', age: 35 }

obj2만 변경되었을 것이라 예상하였는데 둘다 변경되었다. 그 이유는 무엇일까?
이는 Reference type은 할당할때 값이 아닌 데이터의 주소를 저장하기 때문이다.
여기서 얕은 복사와 깊은 복사의 차이가 나타난다.

1-1. Reference 의 얕은 복사, 깊은 복사

얕은 복사? 깊은 복사? 복사이면 복사이지 말이 이상하다.
위에서 언급하였듯이 Reference type은 할당할때 값이 아닌 데이터의 주소를 저장하기 때문에 이런 문제가 발생한다.

다음 그림으로 과정을 살펴보자.

obj 객체를 선언하게 되면 객체에서 할당한 값들이 들어가는 것이 아니라 객체가 생성된 주소가 들어가게 된다.

그럼 이 상태에서 let obj2 = obj는 어떻게 동작할까?

obj2는 obj의 주소를 저장하게 된다. 그렇기 때문에 obj2의 name 값을 변경하게 되면 obj가 가르키는 name의 값까지 한꺼번에 변경되는 것이다. 이를 바로 얕은 복사라고 한다.

얕은 복사란 객체를 복사할 때 위의 예제처럼 원래값과 복사된 값이 같은 참조를 가리키고있는 것을 말한다. 객체안에 객체가 있을 경우 한개의 객체라도 원본 객체를 참조하고 있다면 이를 얕은 복사라고 한다.

그럼 깊은 복사는 어떻게 할 수 있을까?

Primitive type의 경우, 독립적인 메모리에 원시 데이터를 그대로 저장하기 때문에 값을 변경해도 한꺼번에 변경되지 않는다.
Reference type은 데이터의 주소를 저장하기 때문에 이를 방지하기 위에 함수를 제공한다.

배열의 얕은 복사 방지( ... : spread )

let arr1 = [1,2,3];
let arr2 = arr1; 		// 얕은 복사
let arr3 = [...arr1];	// 깊은 복사

console.log( arr1 );
// 출력 결과 : [1,2,3]
console.log( arr2 );
// 출력 결과 : [1,2,3]
console.log( arr3 );
// 출력 결과 : [1,2,3]

arr2[0] = 5;
console.log( arr1 );
// 출력 결과 : [5,2,3]
console.log( arr2 );
// 출력 결과 : [5,2,3]
console.log( arr3 );
// 출력 결과 : [1,2,3]

Object의 얕은 복사 방지( assign )

let obj = {
    name:'jigom',
    age:35,
}

let obj2 = obj;
let obj3 = Object.assign({}, obj);

console.log( obj );
//출력 결과 : { name: 'jigom', age: 35 }
console.log( obj2 );
//출력 결과 : { name: 'jigom', age: 35 }
console.log( obj3 );
//출력 결과 : { name: 'jigom', age: 35 }
obj2.name = 'Tom';
obj3.name = "Jim";

console.log( obj );
//출력 결과 : { name: 'Tom', age: 35 }
console.log( obj2 );
//출력 결과 : { name: 'Tom', age: 35 }
console.log( obj3 );
//출력 결과 : { name: 'Jim', age: 35 }

깊은 복사란, 값 자체의 복사를 나타낸다. 이는 결국 독립적인 메모리에 값 자체를 할당하여 생성하는 것이라 볼 수 있다.

2. undefined? null?

undefined 말 그대로 무엇도 할당되지 않음을 의미한다. 그럼 null과는 어떤 차이가 있을까?

undefined

undefined는 원시값(Primitive Type)으로, 선언한 후에 값을 할당하지 않은 변수나 값이 주어지지 않은 인수에 자동으로 할당된다. 이 값은 전역 객체의 속성 중 하나로, 전역 스코프에서의 변수이기도 하다.

아래의 경우에 변수가 undefined를 반환한다.

값을 할당하지 않은 변수
메서드와 선언에서 변수가 할당받지 않은 경우
함수가 값을 return 하지 않았을 때

null

null은 원시값(Primitive Type) 중 하나로, 어떤 값이 의도적으로 비어있음을 표현한다. undefined는 값이 지정되지 않은 경우를 의미하지만, null의 경우에는 해당 변수가 어떤 객체도 가리키고 있지 않다는 것을 의미한다.

추가 사항

typeof undefined는 출력하면 undefined이다.
typeof null은 출력하면 object이다. 하지만 이는 여전히 원시 타입(primitive value)로, JavaScript에서는 구현 버그로 간주한다.
undefined == null은 true이다.

profile
일단 해보자

0개의 댓글