JavaScript 작동 방식 (시각적으로 설명)
[번역] How JavaScript Works🔥 🤖 (Visually Explained)
JavaScript는 세계에서 가장 사랑받기도 하고 싫어하기도 하는 언어 중 하나입니다. 강력해서 사랑받고, 그리고 JavaScript만 배운다면 풀스택 애플리케이션을 만들 수 있습니다. 또한 여러분이 이 언어를 이해하는데 투자하지 않는다면, JavaScript는 예상치 못하고 혼란스럽게 행동하기 때문에 싫어할 수 있습니다 💔.
이 블로그에서는 브라우저에서 JavaScript가 코드를 실행하는 방법을 설명하고 애니메이션 gif를 통해 학습합니다 😆. 이 블로그를 읽고 나면 록스타 개발자에 한 걸음 더 다가설 것입니다 🎸😎
실행 컨텍스트 Execution Context
“JavaScript의 모든 것은 실행 컨텍스트 안에서 일어납니다.”
저는 모두가 이 말을 필수적으로 기억하기를 바랍니다. 실행 컨텍스트란 브라우저가 일부의 JavaScript 코드를 실행하려고 할 때 호출되는 큰 컨테이너라고 가정할 수 있습니다.
이 컨테이너에서는
- 메모리 구성 요소 (Memory component)
- 코드 구성 요소 (Code component)
로 된 두 개의 구성 요소가 있습니다.
메모리 구성 요소는 변수 환경(variable environment)이라고도 합니다. 이 메모리 구성 요소에는 변수와 함수가 키-값 쌍으로 저장됩니다.
코드 구성 요소는 컨테이너에서 한 번에 한 줄씩 코드가 실행되는 장소입니다. 이 코드 구성 요소에는 ‘실행 스레드(Thread of Execution)‘라는 고급스러운 이름도 있습니다. 멋진 것 같습니다!
Javascript는 동기식 단일 스레드 언어입니다. 한 번에 특정 순서로 하나의 명령만 실행할 수 있기 때문입니다.
코드 실행
간단한 예제를 들어봅시다.
var a = 2;
var b = 4;
var sum = a + b;
console.log(sum);
이 간단한 예제에서는 두 변수, a와 b를 초기화하고 각각 2와 4를 저장합니다.
그런 다음 a 와 b의 값을 더하여 sum 변수에 저장합니다.
JavaScript가 브라우저에서 어떻게 코드를 실행하는지 살펴보겠습니다 🤖
브라우저는 두 가지 구성 요소, 메모리 및 코드 구성 요소로 된 전역 실행 컨텍스트를 만듭니다.
브라우저는 2단계에 걸쳐 JavaScript 코드를 실행합니다.
1> 메모리 생성 단계
2> 코드 실행 단계
메모리 생성 단계에선 JavaScript는 모든 코드를 검사하고 코드의 모든 변수와 함수에 메모리를 할당합니다. 변수의 경우 JavaScript는 메모리 생성 단계에서 undefined로 저장하며 함수의 경우 전체 함수 코드를 유지합니다. 다음 예제를 살펴보겠습니다.
이제 2단계, 즉 코드 실행에서는 전체 코드를 한 줄 한 줄씩 실행하기 시작합니다.
var a = 2를 만나면 메모리의 ‘a’에 2를 할당합니다. 직전까지 ‘a’의 값은 undefined이었습니다.
마찬가지로, b 변수에도 같은 작업을 합니다. ‘b’에 4를 할당하고 sum의 값인 6을 계산하여 메모리에 저장합니다. 이제 마지막 단계에서 콘솔에 sum 값을 프린트한 다음 코드가 완료되면 전역 실행 컨텍스트를 제거합니다.
실행 컨텍스트에서 함수는 어떻게 호출됩니까?
다른 프로그래밍 언어와 비교할 때 JavaScript의 함수는 다르게 동작합니다.
간단한 예제를 살펴봅시다.
var n = 2;
function square(num) {
var ans = num * num;
return ans;
}
var square2 = square(n);
var square4 = square(4);
위의 예제에는 number 타입의 인수를 가져 와서 number의 제곱(square)을 반환하는 함수가 있습니다.
JavaScript는 전역 실행 컨텍스트를 만들고 아래와 같이 코드를 실행할 때 첫 번째 단계에서 모든 변수와 함수에 메모리를 할당합니다.
함수의 경우에는 전체 함수를 메모리에 저장합니다.
여기에 흥미로운 부분이 있는데, JavaScript가 함수를 실행하면 전역 실행 컨텍스트 안에 실행 컨텍스트를 만듭니다.
var a = 2때 처럼, 메모리에 ‘n’에 2를 할당합니다. 2번 라인은 함수라서, 메모리 실행 단계에서 함수는 메모리를 할당받았기 때문에 6번 라인으로 바로 건너뜁니다.
square2 변수는 squre 함수를 호출하고 JavaScript는 새로운 실행 컨텍스트를 만듭니다.
square 함수에 대한 이 새로운 실행 컨텍스트는 메모리 생성 단계에서 함수에 있는 모든 변수에 메모리를 할당합니다.
함수 내의 모든 변수에 메모리를 할당한 후 코드 줄을 한 줄씩 실행합니다. 첫 번째 변수의 2와 같은 num 값을 얻은 다음 ans를 계산합니다. ans가 계산된 뒤 square2에 할당될 값이 반환됩니다.
함수가 값을 반환하면 작업이 완료되었기에 실행 컨텍스트를 삭제합니다.
이제 아래 그림과 같이 7번 라인 또는 square4 변수에 대해서도 유사한 절차를 따릅니다.
모든 코드가 실행되면 전역 실행 컨텍스트도 삭제되는데, 이것이 JavaScript가 우리가 보는 것 뒤에서 코드를 실행하는 방법입니다.
콜 스택 Call Stack
함수를 JavaScript에서 호출하면 JavaScript는 실행 컨텍스트를 만듭니다. 실행 컨텍스트는 함수 안에 함수를 중첩하면 복잡해집니다.
JavaScript는 콜 스택의 도움을 받아 코드 실행 컨텍스트 생성과 삭제를 관리합니다.
스택(“push-down stack”이라고도 함)은 새 항목 추가와 기존 항목 제거가 항상 끝에서 일어나는 순서가 정해진 항목 모음입니다(예: 책 스택).
콜 스택은 여러 함수를 호출하는 스크립트에서 해당 위치를 추적하는 메커니즘입니다.
예를 들어 봅시다.
function a() {
function insideA() {
return true;
}
insideA();
}
a();
함수 ‘a’를 만들고 있으며 이 함수는 true를 반환하는 다른 함수 ‘insideA’를 호출합니다. 이 코드가 바보 같고 아무 일도 하지 않는다는 것은 알지만, JavaScript가 콜백 함수를 처리하는 방법을 이해하는 데 도움이 될 것입니다.
JavaScript가 전역 실행 컨텍스트를 만듭니다. 전역 실행 컨텍스트는 코드 실행 단계에서 함수 ‘a’에 메모리를 할당하고 함수 ‘a’를 호출합니다.
함수 a에 대한 실행 컨텍스트가 만들어지며, 함수 a는 콜 스택에서 전역 실행 컨텍스트 위에 배치됩니다.
함수 a는 메모리를 할당하고 insideA 함수를 호출합니다. 함수 insideA에 대한 실행 컨텍스트가 만들어지고 ‘함수 a’의 콜 스택 위에 배치됩니다.
이제 이 insideA 함수가 true를 반환하고 콜 스택에서 삭제됩니다.
‘함수 a’ 안에 코드가 없기 때문에 실행 컨텍스트가 콜 스택에서 제거됩니다.
마지막으로, 전역 실행 컨텍스트도 콜 스택에서 제거됩니다.