본문 바로가기

자바스크립트

원시자료형 & 참조자료형

- 원시자료형 & 참고자료형

원시 타입(primitive type) 데이터는 고정된 저장공간, 배열과 객체는 저장공간이 유동적으로 늘어날 수 있음

---------------------------------------------------------------------------------------------------------------------------

→ primitive type data : 메모리에 stack이라는 저장공간에 고정된 크기의 저장공간을 할당받아서 데이터를 저장하고 꺼내쓰는데 사용 / 해당 변수명이 이름표처럼 각 공간을 식별하게 해준다.

→ primitive type data : number, boolean, string, undefined, null,  symbol

→ reference type data : 

1)메모리에 stack이라는 저장공간에는 변수명heap영역 어디에 저장되어 있는지 주소값을 저장한다. 

2)heap이라는 저장공간에는 해당주소지에 값을 줄줄이 연결하여 저장한다 (linked형태)

→ reference type data : array, object, function

→ primitive type data는 변수를 할당받는 경우 (ex) let a = b) 해당 변수의 값을 할당받기 때문에 기존 변수에 영향을 주지 않는다.

→ reference type data는 변수를 할당받는 경우 (ex) let a = b) 해당 변수에는 heap영역의 주소값을 할당받기 때문에 기존 변수에 영향을 주게 된다.(같은 값을 사용하게 된다)

원시 자료형은 모두 "하나"의 정보, 즉, 데이터를 담고 있습니다

→  "원시적인" 데이터라고 이야기 하는 이유는 예전에는 데이터 저장소(메모리)의 용량이 제한되어 변수 하나에 데이터 용량이 제한된 하나의 원시 자료형 밖에 담을 수 밖에 없었기 때문이다.

→ 옛날 컴퓨터에서 사용되던 BASIC이라는 컴퓨터 언어의 경우 우리가 알고 있는 string과 number는 쉽게 사용되지만 배열에 상응하는 데이터타입은 잘 사용이 되지 않았으며 구현 가능했더라도 보통 사이즈가 제한되어 있었습니다

→ 참조 자료형은 딱 봐도 하나의 주제는 있지만 분명 서로 다르고, 여러 개의 데이터를 가지고 있는 것을 확인하실 수 있습니다.

→ 원시 자료형의 보관함인 변수에는 하나의 원시 자료형만 담을 수 있습니다. 

→ 원시 자료형의 변수에는 데이터의 크기와는 관계 없이 하나의 데이터만 담을 수 있으며 원시 자료형은 값 자체에 대한 변경이 불가능(immutable)하지만, 변수에 다른 데이터를 할당할 수는 있습니다.

/  ex) "hello world!"

"hello codestates!"

// "hello world!" 와 "hello codestates!"는 모두 변경할 수 없는 고정된 값입니다.

 

let word = "hello world!" 

word = "hello codestates!" 

// 하지만, word라는 변수에 재할당을 하여 변수에 담긴 내용을 변경은 가능합니다.

 

const num1 = 123;

num1 = 123456789; // 에러 발생

// const 키워드로 선언하면, 재할당은 불가합니다.

→ 참조 자료형을 변수에 할당할 때는 변수에 값이 아닌 주소를 저장합니다.

bigint symbol은 특별한 경우 사용하는 데이터 타입

null은 원시 타입과 거의 같게 사용된다.

----------------------------------------------------------------------------------------------------------------

*BigInt : BigIntNumber 원시 값이 안정적으로 나타낼 수 있는 최대치인 

253 - 1보다 큰 정수를 표현할 수 있는 내장 객체입니다.

BigInt는 정수 리터럴의 뒤에 n을 붙이거나(10n) 함수 BigInt()를 호출해 생성할 수 있습니다.

→ ex) const alsoHuge = BigInt(9007199254740991);

// ↪ 9007199254740991n

 

const hugeString = BigInt("9007199254740991");

// ↪ 9007199254740991n

 

const hugeHex = BigInt("0x1fffffffffffff");

// ↪ 9007199254740991n

 

const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");

// ↪ 9007199254740991n

 

BigInt는 내장 Math 객체의 메서드와 함께 사용할 수 없고, 연산에서 Number와 혼합해 사용할 수 없습니다.

BigInttypeof 판별 결과는 "bigint"입니다.

+, *, -, **, % 연산자를 BigInt나 객체로 감싼 BigInt에서 사용할 수 있습니다

/ ex) const expected = 4n / 2n;  // ↪ 2n

 

----------------------------------------------------------------------------------------------------------------

* Symbol() 함수는 심볼(symbol) 형식의 값을 반환하는데, 이 심볼은 내장 객체(built-in objects)의 여러 멤버를 가리키는 정적 프로퍼티와 전역 심볼 레지스트리(global symbol registry)를 가리키는 정적 메서드를 가지며, "new Symbol()" 문법을 지원하지 않아 생성자 측면에서는 불완전한 내장 객체 클래스(built-in object class)와 유사

Symbol()로부터 반환되는 모든 심볼 값은 고유합니다

→ 심볼 값은 객체 프로퍼티(object properties)에 대한 식별자로 사용될 수 있습니다

→ ex) const symbol1 = Symbol();

const symbol2 = Symbol(42);

const symbol3 = Symbol('foo');

 

console.log(typeof symbol1);

// expected output: "symbol"

 

console.log(symbol2 === 42);

// expected output: false

 

console.log(symbol3.toString());

// expected output: "Symbol(foo)"

 

console.log(Symbol('foo') === Symbol('foo'));

// expected output: false

----------------------------------------------------------------------------------------------------------------

* null은 JavaScript의 원시 값 중 하나로, 어떤 값이 의도적으로 비어있음을 표현하며 불리언 연산에서는 거짓으로 취급합니다.  /  null은 객체가 아님

null은 리터럴로서, null로 작성할 수 있습니다

nullundefined와 같은 전역 객체의 식별자가 아닙니다

→ 식별되지 않은 상태를 나타내며 해당 변수가 어떠한 객체도 가리키고 있지 않음을 표시합니다

null 또는 undefined를 검사할 때, 동등 연산자(==)와 일치 연산자(===)의 차이를 주의

----------------------------------------------------------------------------------------------------------------

자바스크립트에서 원시 자료형이 아닌 모든 것은 참조 자료형입니다

→ 배열([])과 객체({}), 함수(function(){})가 대표적이며 이런 자료형을 자바스크립트에서는 참조 자료형(reference data type; 참조 타입)이라고도 부릅니다

→ 컴퓨터가 처음 사용되던 시절에 배열, 즉 리스트라는 개념을 구현하기 어려워서

띄어쓰기, 탭, 쉼표 등으로 데이터를 구분하여 배열과 비슷한 형태로 자료 구조를 구현하기 시작

/  쉼표로 구분된 데이터(comma-separated values)의 형태로 사용

/ ex) 10,20,30,40,50,60

변수에 넣을 수 있는 데이터 크기가 제한되어 있기 때문에 자료 구조를 구현

→  linked list 자료구조의 경우 한정된 크기의 값을 연결하여서 사용

→ "데이터의 크기가 동적으로 변하는" 특별한 데이터 보관함을 구현 = 참조자료형

→ 참조 자료형에는 하나의 데이터가 아닌 여러 데이터가 담기게 된다

→ 참조 자료형의 데이터 자체는 지금까지 배웠던 원시 자료형이 보관되는 데이터 보관함이 아닌 특별한 데이터 보관함에 저장

→ 이 데이터가 위치한 곳(메모리 상 주소)을 가리키는 주소가 변수에 저장

/  특별한 데이터 보관함을 찾아갈 수 있는 주소가 담겨있다.

→ 특별한 데이터 보관함에서는 자기 마음데로 사이즈를 늘렸다가 줄였다가 합니다. ("동적(dynamic)으로 변한다"라고 하기도 합니다.) 

→ 데이터는 별도로 관리되고, 우리가 직접 다루는 변수에는 주소가 저장되기 때문에 reference type이라고 불립니다

→ 특별한 데이터 보관함을 heap이라고도 부릅니다.

→ 레퍼런스(reference)란 컴퓨터 공학에서는 변수가 가리키고(refer)있는 데이터의 참조한다는 의미로 사용

특별한 데이터 보관함은, 왜 동적으로 크기가 변하게 되었을까요?

→ 대량의 데이터가 들어오는 경우는 동영상에서 설명드린 바와 같이, 고정된 데이터 공간을 사용하는 것이 비효율적

→ 크기가 상황에 따라서 커졌다가 작아지는 특별한 데이터 저장소를 만들어 사용하기로 합의하여 별도의 저장공간을 마련하여 따로 관리

→ 변수에는 원시값 혹은 주소만 지정할 수 있고, 주소는 크기가 변하는 특별한 데이터 저장소를 참조하게 되는 것

원시 자료형과 참조 자료형의 특징

→ 원시 자료형이 할당될 때에는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담깁니다.

→ 참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용할 수 있습니다.

----------------------------------------------------------------------------------------------------------------

참조 자료형이 변수에 할당되는 경우는, 변수에 이 데이터가 저장되는 곳의 주소가 할당

let y = x;

변수 x를 변수 y에 할당하는 경우, 변수 x의 값은 참조 자료형이기 때문에 x의 값 { foo: 3 }의 주소를 y에 할당합니다. 값 자체를 할당했던 1번 문제와의 차이점이죠.

이 상태는 변수 x와 변수 y에 모두 같은 { foo : 3 } 이라는 객체의 주소를 바라보고 있습니다.

y.foo = 2;

y.foo = 2, 값이 3이였던 y.foo에 2를 할당을 했습니다. 그러면 x.foo는 무엇일까요? 현재는 같은 주소를 바라보고 있는 y.foo가 2로 변경이 되었으니, 같은 곳을 바라보고 있었던 x.foo도 2가 되어야 합니다.

→ ‘===’의 비교 

참조 자료형의 ===(strict equality)는 주소값이 같은지를 확인합니다. 그렇기 때문에 두 참조 자료형의 주소값은 다르다고 판단을 내릴 수 있습니다.

console.log([1,2,3] === [1,2,3]);

컴퓨터가 위 코드를 읽으면서, 이미 두 개의 heap 저장 공간의 주소를 확보했습니다. 다만 우리는 눈으로 확인하지 못할 뿐입니다. 배열([])과 객체({})등 참조 자료형을 읽을 때, 미리 주소값과 메모리 값을 잡아둔다고 생각하면 편합니다. 그러므로 [] === [] 도 true가 나오지 않는 것이죠.

→ 객체 할당

let y = x;

여기서 변수 y는 x의 주소값을 할당 받았습니다.

y = 2;

하지만 다시 2를 할당 받았습니다.

이 과정 중에서 참조 자료형 { foo : 3 } 에는 아무런 영향을 미치지 않았기 때문에, x.foo를 조회해도 그대로 3이 나오게 됩니다.

→ 배열의 주소값

let myArray = [2, 3, 4, 5];

let ourArray = myArray;

ourArray[2] = 25;

ourArray 주소값에 위치한 배열의 의 2번째 요소를 25로 변경합니다. ourArray와 myArray의 주소값은 같음으로 현재 myArray는 [2, 3, 25, 5] 입니다.

ourArray = undefined;

이제 변수 ourArray에 원시 자료형 undefined가 할당되었기 때문에, myArray에 접근할 수 없습니다. 하지만 myArray는 그대로 [2, 3, 25, 5]입니다.

→ 함수의 호출과 객체

let player = { score: 3 };

function doStuff(obj) { 

  obj.score = 2;

}

 

doStuff(player);

함수 doStuff에 변수 player를 인자로 전달하여 호출합니다. (실행합니다.)

function doStuff(obj) { 

  obj.score = 2;

}

함수가 호출되면 (실행되면) 매개변수 obj에 변수 player의 값이 할당됩니다. { score: 3 }의 주소값이겠죠? obj.score에 2를 할당하면, obj와 player는 같은 주소값을 가지고 있기 때문에, player.score도 2가 되게 됩니다. 

→ 함수의 호출과 변수

let score = 80;

function doStuff(value) {

  value = 90;

}

 

doStuff(score)

함수 doStuff에 score의 값을 인자로 전달하여 실행합니다.

function doStuff(value) {

  value = 90;

}

매개변수 value에 score의 값 80이 전달되고,

value = 90에서 value에 90이 할당됩니다.

다만 변수 score의 값 80은, 참조 자료형이 아니기 때문에 주소값을 전달하지 않고, 값 자체를 복사하여 전달하게 됩니다. 그래서 함수에서 어떤 일이 발생했던가와 관련이 없이 score는 초기에 할당된 값 80이 그대로 유지됩니다

----------------------------------------------------------------------------------------------------------------

 

'자바스크립트' 카테고리의 다른 글

클로저(closure)의 전반적인 개념  (0) 2021.05.07
스코프(scope)의 전반적인 개념  (0) 2021.05.07
정규표현식  (0) 2021.05.07
배열&객체의 전반적인 개념  (0) 2021.05.07
반복문  (0) 2021.05.07