아래 적힌 내용은 코어 자바스크립트를 참조해서 제 생각과 책 내용을 합친 내용입니다. 더 많은 지식을 얻고 싶으시다면, 코어 자바스크립트를 정독하는 것을 추천드립니다.
기본형(Primitive)과 참조형(Reference)
자바스크립트의 타입은 기본형과 참조형 두가지로 나뉘어지게 되는데, 기본형은 Number, String, boolean, Symbol, undefined, null 이렇게 여섯가지 그리고 참조형은 객체, 배열, 등등이 존재하고 있습니다.
기본형이라는 것 중에서 중요한 것은 불변성(Immutability)를 띄는 것을 의미하는데, 불변성의 의미를 잘 파악하고 있어야 된다고 생각해요. 왜냐하면, 일단 var a = 10; 이라고 하고 a = 15라고 변경을 해서 console을 찍어보면 15라고 잘 나오는데, 이건 변화를 한거잖아요? 근데 이는 불변성입니다. 왜 불변성인지는 아래 내용에서 설명을 할 예정입니다.
들어가기전, 식별자(Identifier)와 변수(Variable)를 먼저 설명하겠습ㄴ디ㅏ.
식별자와 변수는 서로 헷갈릴 수 있는 부분이 될 수 있습니다. 어떨때는 식별자 어떨때는 변수로 설명하는데, 식별자는 어떤 데이터(변수라고 칭할 수 있음)를 식별하는 데 사용하는 이름을 의미합니다. 그리고 변수는 변할 수 있는 수(숫자, 문자열, 객체, 배열)이라고 부릅니다.
제 생각에는 var a에서 a가 식별자가 되겠죠? 우리는 메모리에 할당되어있는 이런 변수를 식별할때 우리가 붙여준 이름으로 검색을 하게 될것입니다. 그것이 식별자가 됩니다. 그래서 "a는 식별자이다."라고 말할 수 있을 것 같습니다. 변수는 무엇일까요? var a = 10; 10이 변수가 되겠죠? 우리는 이 값이 변할 수 있다는 것을 알고 있습니다. 15가 될수도 'string'이 될 수도 있겠죠? 그래서 이를 변수라고 부르게 됩니다.
그래서 자바스크립트는 변수 선언과 할당을 어떻게 할 수 있을까?
이 내용은 코어 자바스크립트 저자의 방식으로 설명드릴것입니다. 변수가 할당되는 영역 그리고 데이터가 할당되는 영역 두가지로 나뉘어서 설명했습니다. 이는 책을 읽는 사람의 이해를 더욱 빠르게 하기 위해 저자가 만들어낸 개념이며 이를 바탕으로 설명을 하겠습니다.
var a = 'abc'라는 코드를 작성했습니다. 식별자 a에 변수 'abc'를 담는 코드가 생성이 된 것입니다. 메모리에서 비어있는 공간을 확보하고 그 공간의 이름을 a라고 선언했습니다. 그리고 a라는 이름을 가진 주소를 검색해 문자열을 할당하면 되지만, 그렇지 않습니다.
실제로는 'abc'가 할당된 메모리의 주솟값을 참조하는 형태로 이루어집니다. 즉, a라는 이름을 가진 메모리는 'abc'가 할당된 메모리의 주솟값을 참조하고 있다고 이해하면 됩니다.
자바스크립트는 숫자형 데이터에 대해 64비트의 공간을 확보하도록 설계되어 있는데요. 변환되는 값들이 전부 숫자라면 큰 문제는 발생하지 않을 것 입니다. 다만 엄청나게 어마무시한 숫자가 적용된다면 문제가 발생할 수도 있다고 생각이되는데, 이 부분은 찾아봐야할 것 같습니다.
이때, 숫자가 아닌 문자열을 할당해준다면 어떻게 이루어질까요? 64비트로는 문자열을 만족시키지 못한 수도 있습니다. 그렇다면 변환한 데이터를 다시 저장하기 위해서 우리는 확보한 공간을 늘려주는 과정을 거치게 될 것입니다.
맨 뒤에 메모리 공간이 위치해서 그냥 뒤에 메모리를 확보만한다면 그건 쉬운 문제가 될 것입니다. 하지만 해당 메모리의 위치가 다른 할당된 메모리 사이에 끼어버린다면? 두번의 과정을 거쳐야합니다. 뒤에 위치하고 있는 메모리를 옮기고, 현재 메모리에게 할당을 해주고 문자열을 저장해야합니다. 이 과정은 운영체제에서 프로세스 연속 메모리 할당에서 발생하는 문제와도 비슷한데요. 연속적으로 할당되어야 하지만 외부 단편화가 발생되어 할당하지 못하는 상황이 발생되게 됩니다. 그때 우리는 압축 또는 통합으로 메모리 공간을 확보하게 되었습니다. 이렇게 된다면, 실시간 서비스를 진행하는 프로세스는 중단이 될 수 밖에 없는 문제가 발생해, UX에 좋지 못한 경험을 제공하게 되겠죠? 자바스크립트도 그러합니다. 그래서 아예 새로운 메모리를 할당해 다시 참조하는 방식으로 설계를 진행했습니다.
예를 들어 number 1을 'abcefg...'로 변환하게 된다면? 새로운 값을 할당해 다시 참조하는 방식이 될것입니다.
여기서는 또 다른 이점이 있습니다. 500개의 변수를 만드는데, 변수 공간은 당연히 500개가 필요할 것입니다. 근데 값을 500개를 만들어줄 필요가 있을까요?
하나의 공간에만 만들어두고 참조하는 형식으로 한다면 더욱 효율적으로 메모리를 사용하지 않을까요?
(500 * 2(주소공간의 크기) + 500 * 8(숫자의 크기)) 보다는 500 * 2(주소공간의 크기) + 8(숫자의 크기)로 만들어 준다면 상당히 효율적으로 메모리를 할당해줄 수 있습니다.
자바스크립트는 이렇게 메모리를 할당해줍니다. 여기서 주의할 점은 코어자바스크립트 저자가 새로운 개념을 말한것입니다. 실제로 변수 영역, 데이터 영역으로 나뉘어지는지는 알 수 없습니다. 이해하기 쉽게 개념을 덧 붙인 것입니다.
불변값(Immutability)란 그렇다면 무엇일까?
불변값이라는 것은 제 개인적인 생각입니다. 일단 위에서 설명했듯이 식별자가 저장되어있는 변수 데이터는 데이터 변수의 주소를 가리키는 형식으로 이루어져 있습니다. 근데 위에서도 설명드렸듯 데이터를 변화주려고 한다면 어떻게 할까요? 바로 새로운 데이터 메모리를 만들어서 재 할당해주는 방식을 취하고 있습니다. 그것은 이전에 있던 데이터 값을 재활용하는 것이 아니라, 재할당을 해주는 것입니다. 그래서 이렇게 보면 이미 만들어진 값은 불변하다는 것을 알 수 있습니다. 그렇게 되면 계속해서 메모리에 데이터 값이 계속해서 생긴다면? 메모리는 부족해지지 않을까라는 생각을 당연히 할 수 있습니다. 물리적으로 한정된 크기를 갖고 있기 때문인데요. 그것 또한 자바스크립트가 가비지 컬렉팅(Garbage Collecting)이라는 방법을 사용해 메모리를 다시 회수합니다. 가비지 컬렉팅이란 참조하고 있는 것이 없다면 사라지게 된다는 것인데요. 이에 대해서는 나중에 자세히 찾아보고 공부해서 설명해보고 싶습니다. 어쨌든, 한번 할당한 데이터의 값은 불변한다는 것 그 값이 불변값(Imuutability)입니다.
이제는 가변값(Variable)이란 무엇일까?
참조형 데이터를 얘기할때 저는 이렇게 얘기하는 편입니다.
var a = 5;
var b = {
a: 1,
b: 'bbb'
};
일단 기본형을 저장하는 a와 참조형을 저장하는 b는 똑같이 적용이 될 것입니다. 변수 메모리 영역에 똑같이 적용이 될텐데, 기본형과 참조형의 차이가 되겠습니다. 기본형은? 데이터 메모리에 메모리를 할당받아서 만들게 되겠죠? 근데 참조형은 하나의 객체입니다. 객체 안에는 또 다른 기본형 값이 들어 있거나 참조형이 들어가게 되겠습니다. 그래서 다시 객체가 참조할 수 있는 메모리를 다시 할당하게 됩니다. 그 객체가 이제 기본형의 값들을 참조하는 위의 내용처럼 다시 메모리 영역을 할당받아 선언이 될 것입니다.
이처럼 생각하면 편하게 이해할 수 있을 것이라 생각됩니다.
참조형은 객체의 변수(프로퍼티) 영역이 별도로 존재하고 있습니다.
객체가 별도로 할애한 영역은 변수 영역일 뿐 데이터 영역은 기존의 메모리 공간을 그대로 활용하고 있습니다. 데이터 영역에 저장된 값은 모두 불변값입니다. 그러나 변수에는 다른 값을 얼마든지 대입할 수 있습니다. 바로 이 부분 때문에 흔히 참조형 데이터는 불변하지 않다(가변값)라고 하는 것입니다.
null과 undefined
undefined부터 말씀드리자면, 사용자가 명시적으로 지정할 수도 있습니다. 명시적이라는 것은 사용자가 직접 undefined라고 할당할 수 있다는 것이 됩니다. 그리고 자바스크립트 엔진이 자동으로 부여하는 경우도 있습니다.
자바스크립트 엔진은 사용자가 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로는 그렇게 하지 않을 때 undefined를 반환하게 되는데요. 이것을 어떤 상황에서 반환하게 되는지 아래 세가지로 보여드리겠습니다.
(1) 값을 대입하지 않은 변수, 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
(2) 객체 내부의 존재하지 않는 프로퍼티에 접근하려고 할 때
(3) return 문이 없거나 호출되지 않는 함수의 실행 결과
- 실제로 async function이 아무것도 반환하지 않는다면? Promise<undefined>를 반환하게 됩니다.
사용자가 명시적으로 부여한 경우, 비어있는 요소에 접근하려 할 때 반환되는 경우
두 경우의 undefined의 의미를 구분할 수 있겠습니다. 전자의 undefined는 그 자체로 값입니다. undefined가 비록 비어있음을 의미하긴 하지만 하나의 값으로 동작하기 때문에 이때의 프로퍼티나 배열의 요소는 고유의 키값이 실존하게 됩니다. 따라서 순회의 대상이 될 수 있습니다.
아무것도 하지 않은 채로 접근했을 때 자바 스크립트 엔진이 반환해주는 undefined는 해당 프로퍼티 내지 배열의 키값(인덱스) 자체가 존재하지 않습니다. 값으로써 어딘가에 할당된 undefined는 실존하는 데이터인 반면, 자바스크립트 엔진이 반환해주는 undefined는 문자 그대로 값이 없음을 나타냅니다.
실제로 우리가 undefined를 사용할 이유는 없습니다. null이라는 값이 별도로 존재하기 때문입니다. 그래서 비어있음을 명시적으로 나타내고 싶을 때는 undefined가 아니라 null을 사용하면 됩니다.
기본형과 참조형
추가적으로 파악해보면 좋을 내용
- 기본형의 데이터는 스택(Stack) 메모리에 저장되며, 값이 변경될 때마다 새로운 값이 생성됩니다.
- 참조형 데이터는 힙(Heap) 메모리에 저장되며, 변수는 힙에 저장된 데이터를 참조하는 주소값을 스택에 저장합니다.
식별자(Identifier)와 변수(Variable)
보완이 필요한 내용
- 식별자와 변수의 차이에 대해 설명은 명확하지만, 변수의 정의에서 데이터 그 자체와 혼동이 있었습니다. 변수는 메모리 상에 값이 저장된 위치(주소)를 나타내는 이름으로, 값이 곧 변수는 아닙니다.
추가적으로 파악해보면 좋을 내용
- 변수는 "값을 담는 컨테이너"가 아니라, 값을 참조하는 이름입니다. 변수에 할당된 값이 메모리에 위치한 주소를 통해 참조되므로, 변수는 메모리와 값 사이의 연결 고리 역할을 합니다.
메모리 할당 과정
틀린 내용 및 보완
- "64비트로 설계된 공간"에 대한 설명은 다소 불명확합니다. 숫자는 IEEE 754 표준을 따르는 64비트 부동소수점 형식으로 저장되지만, 자바스크립트의 문자열이나 객체는 이와 무관하게 힙 메모리에 저장됩니다.
추가적으로 파악해보면 좋을 내용
- 자바스크립트는 콜스택(Call Stack)과 힙(Heap)을 활용하여 메모리를 관리합니다.
- 콜스택: 함수 호출, 기본형 데이터 등을 저장.
- 힙: 객체, 배열 등 참조형 데이터를 저장.
4. 불변성(Immutability)
추가적으로 파악해보면 좋을 내용
- 기본형의 불변성: 값 자체를 변경할 수 없으며, 변경 시 항상 새로운 메모리를 생성합니다.
- **참조형의 "불변성"**은 객체가 불변한 것이 아니라, 객체가 참조하는 값이 불변하지 않다는 점에서 오해를 유발할 수 있습니다.
5. 가비지 컬렉션(Garbage Collection)
추가적으로 파악해보면 좋을 내용
- 자바스크립트의 가비지 컬렉션은 참조 카운팅(Reference Counting) 및 마크 앤 스위프(Mark-and-Sweep) 알고리즘을 사용합니다.
- 참조 카운팅: 더 이상 참조되지 않는 객체를 메모리에서 해제.
- 마크 앤 스위프: 도달할 수 없는 객체를 식별하여 메모리에서 해제.
6. null과 undefined
틀린 내용 및 보완
- "undefined를 사용하지 않아야 한다"는 주장에는 주의가 필요합니다. 실제로 특정 상황에서 undefined를 사용하는 경우도 있으며, 완전히 배제할 필요는 없습니다. 예를 들어, 함수에서 반환값이 없는 경우 undefined를 암시적으로 반환합니다.
추가적으로 파악해보면 좋을 내용
- undefined는 변수에 값이 할당되지 않은 상태를 나타내며, 이는 자바스크립트 엔진에 의해 자동 처리됩니다.
- null은 개발자가 명시적으로 설정하는 값으로, "값이 없음을 의도적으로 표현"하는 데 사용됩니다.
요약 (Summary)
- 기본형과 참조형
- 기본형 데이터는 불변성을 가지며, 값 변경 시 새로운 메모리를 할당받습니다.
- 참조형 데이터는 힙 메모리에 객체를 저장하며, 변수는 해당 객체의 주소를 참조합니다.
- 메모리 관리
- 자바스크립트는 스택과 힙을 활용해 메모리를 관리하며, 가비지 컬렉션으로 참조되지 않는 데이터를 회수합니다.
- 불변성
- 기본형 데이터는 불변성을 가지며, 참조형 데이터는 객체 내부 값이 변경 가능하므로 가변성으로 간주됩니다.
- null과 undefined
- undefined는 자바스크립트 엔진이 자동으로 부여하거나 명시적으로 할당할 수 있습니다.
- null은 명시적으로 "값이 없음"을 나타낼 때 사용됩니다.
'Language > Javascript' 카테고리의 다른 글
클로저란 무엇인가요? (0) | 2024.12.04 |
---|---|
실행 컨텍스트(Execution Context)에 대해서 (2) | 2024.12.01 |