들어가며
최근 모던 자바스크립트 딥 다이브 책을 읽고 있는데요.
scope에 대해 어느 정도 지식을 가지고 있었지만 좀 더 상세하게 알게 되면서
“당연히 코드 블록 안에 있으니까 쓸 수 있는 거지”가 아니라
누군가에게 설명해 줄 수 있으면 좋겠다는 생각을 가지게 되었습니다.
또한 읽으면서 Javascript 구동방식에 좀 더 이해하게 되는 좋은 지식을 공유하려고 합니다.
scope란?
scope는 Javascript뿐만 아니라 모든 프로그래밍 언어에서 가장 기본적이고도 중요한 개념입니다! 프로그램언어에서 변수에 접근할 수 있는 범위를 의미하죠.
scope에는 global(전역), local(지역) 2개의 범위가 존재합니다!
global scope
const name = 'Noh'; // 전역 scope에 변수 name을 선언하고 값 'Noh'를 할당합니다.
function show() {
console.log(name); // 함수 내부에서 전역변수 name을 참조하고 값 'Noh'를 출력합니다.
}
show(); // show 함수를 호출합니다. 함수 내부에서 전역변수 name을 참조하여 'Noh'를 출력합니다.
console.log(name); // 전역 scope에서 변수 name을 참조하고 값 'Noh'를 출력합니다.
이처럼 전역 scope에서 선언된 변수는 해당 scope 내에서 어디에서든지 참조할 수 있습니다! 함수 내부에서 전역 변수에 접근할 수 있고, 함수 외부에서도 전역 변수에 접근할 수도 있죠!
local scope
function show() {
const name = 'Noh'; // 지역 scope(함수)에 지역변수 name을 선언하고 값 'Noh'를 할당합니다.
console.log(name); // 함수 내부에서 지역변수 name을 참조하고 값 'Noh'를 출력합니다.
}
show(); // show 함수를 호출합니다. 함수 내부에서 지역변수 name을 참조하여 'Noh'를 출력합니다.
console.log(name); // 전역 scope에서 지역변수 name을 참조하려고 하지만, name은 지역 scope(함수) 내부에서 선언되었기 때문에 참조할 수 없습니다. 따라서 에러가 발생합니다.
지역 scope는 해당 scope 내에서 선언된 변수들이 유효하며, 해당 scope 외부에서는 접근할 수 없습니다.
이를 통해 변수의 유효 범위를 제한하고, 코드의 모듈화와 캡슐화를 구현할 수 있는거죠!
scope chain
scope chain은 함수가 중첩된 경우에 형성됩니다! 함수안에 함수가 정의될 수가 있겠죠.
함수가 변수 또는 함수를 참조할 때, JavaScript 엔진은 현재 scope에서 해당 식별자를 찾고,
찾지 못하면 상위 scope로 이동하여 다시 검색합니다.
이 과정을 scope chain이라고 합니다!
function outer() {
var outerVar = 'Outer';
function inner() {
var innerVar = 'Inner';
console.log(innerVar); // 'Inner'
console.log(outerVar); // 'Outer'
console.log(globalVar); // 'Global'
}
inner();
}
var globalVar = 'Global';
outer();
console.log(globalVar); // 'Global'
console.log(outerVar); // ReferenceError: outerVar is not defined
console.log(innerVar); // ReferenceError: innerVar is not defined
보기 코드에서 가장 내부 함수인 inner에서는 outerVar, globalVar 변수에 접근이 가능하지만
전역 scope인 outer 함수 밖에서는 접근을 할 수가 없습니다!
scope chain에 관한 변수의 유효 범위가 좀 더 이해가 가셨을까요!?
깜짝 문제
이제 scope에 대해 마스터하신 것 같나요??
해당 문제를 한번 풀고 가봅시다!
var x = 1; // global
function one() {
var x = 10;
two();
}
function two() {
console.log(x);
}
one(); // ?
two(); // ?
정답을 맞히셨을까요??
정답은 1 1 입니다.
저는 전에 내용을 보고 one() 함수가 호출되면
two() 함수가 호출되어 scope chain으로 내부 변수 var x = 10 참조할 줄 알았지만
두 함수 모두 전역변수 1을 참조하는데요!
이걸 이해하려면 렉시컬 스코프(lexical scope)를 이해해야 해요!
렉시컬 스코프(lexical scope)
JavaScript는 렉시컬 스코프를 따르는 언어입니다.
렉시컬 스코프는 어디서 선언이 되었나가 중요합니다!
그 반대인 동적 스코프라면 어디서 호출이 되었나가 중요하고요!
렉시컬 스코프를 생각하면 전역 scope에 two함수가 선언이 되어서 전역 변수를 참조하는걸 볼 수 있습니다!
하지만 동적 스코프였다면 즉 one함수에서 호출이되는게 중요하여 내부 one함수에 내부 변수 var x=10을 참조했을 겁니다!
렉시컬 스코프는 선언된 곳에서 상위 scope를 참조한다! 꼭 같이 기억해 봐요!
마치며
JavaScript에서 가장 기본적인 개념을 공부해 보았는데요.
이전에 공부할 때는 scope는 범위 같은 개념이구나 하고 얼렁뚱땅 넘어갔는데
이젠 누군가가 질문을 하게 된다면 “당연히 그렇게 쓰는 거죠” 가 아니라 확실히 설명해 줄 수 있는 자신감이 생겼습니다.
이후에 연결되는 실행 컨텍스트와 클로져 개념에 필수적인 지식 개념이기도 합니다.
이후 다른 챕터 공부에서도 이해가 잘될 수 있게 징검다리 역할을 해준 개념이기도 합니다.