1장 데이터 타입
자바스크립트 데이터 타입에는 크게 두 가지가 있습니다.
그림을 보시면 하위분류에 속하는 타입들을 보실 수 있습니다.
어떤 기분으로 기본형과 참조형을 구분하는 걸까요?
기본형은 값이 담긴 주솟값을 바로 복제하는 반면
참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제하는 점이 다릅니다.
또한 기본형은 불변성을 띕니다.
이 불변성을 제대로 이해하기 위해 자바스크립트가 메모리 영역에서 어떻게 처리되는지 알아봅시다.
데이터 타입에 관한 배경지식
메모리와 데이터
0또는 1만 표현할 수 있는 하나의 메모리 조각을 비트(bit)라고 합니다.
각 비트는 고유한 식별자를 통해 위치를 확인할 수 있습니다.
매우 많은 비트를 한 단위로 묶으면 검색시간을 줄일 수도 있고 표현할 수 있는 데이터의 개수도 늘어납니다.
하지만 동시에 낭비되는 비트가 생기기도 합니다.
이러한 문제 때문에 바이트(byte)라는 단위가 생겼습니다.
1바이트는 8개의 비트로 구성되어 있습니다.
1 비트마다 0 또는 1의 두 가지 값을 표현할 수 있어 1 바이트는 총 256(2^8) 개의 값을 표현할 수 있습니다.
식별자와 변수
변수는 '변할 수 있는 수'입니다. 반드시 숫자여야 하는 것은 아닙니다.
식별자는 어떤 데이터를 식별하는 데 사용하는 이름. 즉 변수명입니다.
변수 선언과 데이터 할당
변수 선언
var a;
이 코드를 말로 풀어쓰면 "변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a로 한다"가 됩니다
변할 수 있는 데이터 이기 때문에 선언할 때는 undefined이더라도 나중에 다른 값으로 바꾸면 됩니다
변수는 결국 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇이라고 생각할 수 있습니다.
데이터 할당
var a; //변수 a 선언
a = 'abc'; //변수 a에 데이터 할당
var a = 'abc'; //변수 선언과 할당을 한 문장으로 표현
선언과 할당을 두 문장으로 나누어 명령하든 4번째 줄과 같이 한 문장으로 명령하든, 자바스크립트 엔진은 결국 같은 동작을 수행합니다.
왜 변수 영역에 값을 직접 대입하지 않고 굳이 번거롭게 한 단계를 더 거치는 걸까요?
이는 데이터 변환을 자유룝게 할 수 있으며 메모리를 효율적으로 관리할 수 있기 때문입니다.
기본형 데이터와 참조형 데이터
불변값
변수와 상수를 구분하는 성질은 '변경 가능성'입니다.
바꿀 수 있으면 변수, 바꿀 수 없으면 상수입니다.
변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리입니다.
한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부를 구분할 때
변경 가능성의 대상이 바로 데이터 영역 메모리입니다.
기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변값입니다.
가변값
기본형 데이터가 모두 불변값이라면 참조형 데이터는 모두 가변값일까요?
기본적인 성질은 가변값인 경우가 많지만 설정에 따라 불변값이 될 수도 있습니다.
불변 객체
불변 객체를 만드는 간단한 방법
불변 객체는 최근에 React, Vue.js, Angular 등의 라이브러리나 프레임워크에서 뿐만 아니라 함수형 프로그래밍, 디자인 패턴에서도 매우 중요한 기초가 되는 개념입니다.
데이터 자체를 변경하고자 하면 기존 데이터는 변하지 않습니다.
그렇다면 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당하기로 규칙을 정하거나 자동으로 새로운 객체를 만드는 도구를 활용한다면 객체도 불변성을 확보할 수 있습니다.
불변 객체가 필요한 상황은?
값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우!
얕은 복사와 깊은 복사
얕은 복사는 바로 아래 단계의 값만 복사하는 방법이고, 깊은 복사는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법입니다.
어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때, 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만 참조형 데이터는 다시 그 내부의 프로퍼티들을 복사해야 합니다.
이 과정을 참조형 데이터가 있을 때마다 재귀적으로 수행해야만 깊은 복사가 됩니다.
undefined와 null
undefined는 사용자가 명시적으로 지정할 수도 있지만 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여합니다.
사용자가 명시적으로 지정하는 경우는 달리 덧붙일 내용이 없어 넘어갑니다.
자바스크립트 엔진은 사용자가 어떤 값을 지정할 것이라고 예상되는 상황에도 실제로는 그렇게 하지 않았을 때 undefined를 반환합니다.
'비어있음'을 명시적으로 나타내고 싶을 때는 undefined가 아닌 null을 쓰면 됩니다.
null은 애초부터 이런 용도로 만든 데이터타입입니다.
null은 주의할 점이 있습니다. typeof null이 object라는 점입니다.
이는 자바스크립트 자체 버그입니다.
따라서 어떤 변수의 값이 null인지 여부를 판별하기 위해서는 typeof 대신 다른 방식으로 접근해야 합니다.
2장 실행 콘텍스트
실행 콘텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체로 자바 스크립트의 동적언어로서의 성격을 가장 잘 파악할 수 있는 개념입니다.
실행 컨텍스트는 자바스크립트에서 가장 중요한 핵심 개념 중 하나입니다. 정확히 이해하는 것이 일반적인 개발자로서의 실력 향상에 큰 도움이 될 것입니다.
실행 콘텍스트란?
실행 콘텍스트를 살펴보기 앞서 스택과 큐의 개념을 살펴봅시다.
스택은 출입구가 하나뿐인 깊은 우물 같은 데이터구조입니다.
비어있는 스택에 순서대로 a, b, c, d를 저장했다면 꺼낼 때는 반대로 d,c,b,a의 순서로 꺼낼 수 밖에 없습니다.
이 방식을 LIFO(Last In First Out)으로 후입선출 방식의 대표적 예라고 볼 수 있습니다.
한편 큐는 양쪽이 모두 열려있는 파이프를 떠올리면 됩니다.
종류에 따라 양쪽 모두 입력과 출력이 가능한 큐도 있으나 보통은 한쪽은 입력만, 다른 한쪽은 출력만을 담당하는 구조를 말합니다.
이 경우 비어있는 큐에 순서대로 데이터 a,b,c,d를 저장했다면 꺼낼 때도 역시 a, b, c, d의 순서대로 꺼낼 수밖에 없습니다.
이 방식을 FIFO(First In First Out)으로 선입선출 방식의 대표적 예라고 볼 수 있습니다.
동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 콘텍스트를 구성하고, 이를 콜 스택에 쌓아 올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장합니다.
여기서 '동일한 환경' 즉 하나의 실행 콘텍스트를 구성할 수 있는 방법으로 전역공간, eval()함수, 함수 등이 있습니다.
자동으로 생성되는 전역공간과 악마로 취급받는 eval을 제외하면 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것뿐입니다.
inner 함수 내부에서 a 병수에 값 3을 할당하고 나면 inner함수의 실행이 종료되면서 inner 실행 콘텍스트가 콜 스택에서 제거됩니다.
그러면 아래에 있던 outer콘텍스트가 콜 스택의 맨 위에 존재하게 되므로 중단했던 다음 줄부터 이어서 실행합니다.
a변수의 값을 출력하고 나면 outer함수의 실행이 종료되어 outer 실행 컨텍스트가 콜 스택에서 제거되고, 콜 스택에는 전역 콘텍스트만 남아있게 됩니다. 그런 다음, 실행을 중단했던 다음 줄부터 이어서 실행합니다.
a변수의 값을 출력하고 나면 전역 공간에는 더는 실행할 코드가 남아있지 않아 전역 콘텍스트도 제거되고, 콜 스택에는 아무것도 남지 않은 상태로 종료됩니다.
스택 구조를 잘 살펴보면 한 실행 콘텍스트가 콜 스택의 맨 위에 쌓이는 순가이 곧 현재 실행할 코드에 관여하게 되는 시점임을 알 수 있습니다.
기존의 콘텍스트는 새로 쌓인 컨텍스트보다 아래에 위치할 수 밖에 없기 때문이다. 이렇게 어떤 실행 컨텍스트가 활성화 될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는 데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장합니다.
VariableEnvironment
VariableEnvironment에 담기는 내용은 LexicalEnvironment와 같지만 최초 실행 시의 스냅숏을 유지한다는 점이 다릅니다.
실행 콘텍스트를 생성할 때 VariableEnvironment에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LexicalEnvironment를 만들고, 이후에는 LexicalEnvironment를 주로 활용합니다.
LexicalEnvironment
lexical environment은 정적 환경이라는 뜻으로 여기서 '정적'이란 수시로 변하는 환경 정보를 의미합니다.
environmentRecord와 호이스팅
environmentRecord에는 현재 콘텍스트와 관련된 코드의 식별자 정보들이 저장됩니다.
콘텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우그 함수 자체,
var로 선언된 변수의 식별자 등이 식별자에 해당합니다.
컨텍스트 내부 전체를 처음부터 끝까지 훑어나가며 순서대로 수집합니다.
호이스팅 규칙
environmentRecord에는 매개변수의 이름, 함수 선언, 변수명 등이 담깁니다.
이 상태에서 변수 정보를 수집하는 과정, 즉 호이스팅을 처리해 봅시다.
environmentRecord는 현재 실행된 콘텍스트의 대상 코드 내에 어떤 식별자들이 있는지만 관심이 있고,
각 식별자에 어떤 값이 할당될 것인지는 관심이 없습니다.
따라서 변수를 호이스팅 할 때 변수명만 끌어올리고 할당 과정은 원래 자리에 그대로 남겨둡니다.
매개변수의 경우에도 environmentRecord의 관심사에 맞춰 수집대상 1,2,3을 순서대로 끌어올리고 나면 다음과 같은 형태로 바뀝니다.
함수 선언문과 함수 표현식
함수 선언문으니 function 정의부만 존재하고 별도의 할당 명령이 없는 것을 의미합니다.
반대로 함수 표현식은 정의한 function을 별도의 변수에 할당하는 것을 말합니다.
함수 선언문의 경우 반드시 함수명이 정의되어 있어야 하는 반면, 함수 표현식은 없어도 됩니다.
함수를 정의 한 함수 표현식을 '기명 함수 표현식', 정의하지 않은 것을 '익명 함수 표현식'이라고 부르기도 하는데,
일반적으로 함수 표현식은 익명 함수 표현식을 말합니다.
참고
기명 함수 표현식 주의할 점
외부에서는 함수명으로 함수를 호출할 수 없다는 점입니다.
함수명은 오직 함수 내부에서만 접근할 수 있습니다.
스코프, 스코프 체인, outerEnvironmentReference
스코프란 식별자에 대한 유효범위입니다.
어떤 경계 A의 외부에서 선언한 변수는 A의 외부뿐 아니라 A의 내부에서도 접근이 가능하지만,
A의 내부에서 선언한 변수는 오직 A의 내부에서만 접근할 수 있습니다.
이러한 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해 나가는 것을 스코프 체인이라고 합니다. 그리고 이를 가능하게 하는 것이 바로 LexicalEnvironment의 두 번째 수집 자료인 outerEnvironmentReference입니다
스코프 체인
outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조한다.
여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능하다.
표의 전체 윤곽을 왼쪽에서 오른쪽으로 바라보면 '전역 콘텍스트 > outer 컨텍스트 > inner 콘텍스트' 순으로 점차 규모가 작아지는 반면, 스코프 체인을 타고 접근 가능한 변수의 수는 늘어납니다.
전역 공간에서는 전역 스코프에서 생성된 변수에만 접근할 수 있습니다.
outer함수 내부에서는 outer 및 전역 스코프에서 생성된 변수에 접근할 수 있지만
inner 스코프 내부에서 생성된 변수에는 접근하지 못합니다.
innter 함수 내부에서는 inner, outer, 전역 스코프 모두에 접근할 수 있습니다.
전역변수와 지역변수
전역 공간에서 선언한 변수는 전역변수
함수 내부에서 선언한 변수는 무조건 지역변수입니다.
this
실행 콘텍스트의 thisBuilding에는 this로 지정된 객체가 저장됩니다.
실행 컨텍스트 활성화 당시에 this가 지정되지 않은 경우 this는 전역 객체가 저장됩니다.
'코어자바스크립트 스터디' 카테고리의 다른 글
5장 클로저 (0) | 2024.07.15 |
---|---|
3,4강 발표자료 (0) | 2024.07.13 |
4장 콜백함수 (0) | 2024.07.10 |
3장 this (0) | 2024.07.08 |
코어 자바스크립트 - 1장 : 데이터 타입 (0) | 2024.07.03 |