함수 스코프와 블록 스코프
javascript의 함수 스코프와 블록 스코프에 대해서 알아본다
Javascript에서의 스코프에 대해서 알아보고자 합니다.
Scope
그 전에, 우선 스코프란 무엇일까요? 스코프(scope)란 단어는 범위를 뜻합니다. Javascript에서 쓰이는 스코프의 범위란 변수에 접근할 수 있는 범위를 의미합니다.
Javascript에서 쓰이는 Scope는 크게 2가지 유형의 Scope가 있습니다.
바로 블록 스코프, 함수 스코프 가 있습니다.
함수 스코프
기본적으로 Javascript는 함수 스코프를 사용합니다. 각 함수는 새로운 스코프를 만들고, 함수 내부에 정의된 변수는 함수 외부에서는 접근할 수 없습니다.
다만 만약 변수가 함수 내부에 선언된 것이 아니라면, 변수의 스코프는 전역 스코프가 되어 어디서든 접근이 가능해 집니다.
function(){
var value = 123;
}
console.log(value); // reference error위 코드에서 처럼 함수 내부에 정의된 변수를 외부에서는 접근할 수 없습니다. 하지만 함수 스코프에서 스코프를 생성하는 것은 어디까지나 함수이기 때문에 함수가 아닌 곳에서 사용된 값들은 외부에서도 사용할 수 있게 됩니다.
if(true){
var value = 123;
}
console.log(value); // 123
var temp = [];
for(var i = 0; i<5; i++){
temp.push(function(){
return i;
});
}
console.log(i) // 5
temp.forEach(v=>{
console.log(v()); // 5 5 5 5 5
})위 코드와 같이 코드를 실행하면 이상한 결과를 얻게 됩니다.
우선 value는 분명 if 문으로 둘러 쌓여 있지만, 이는 함수가 아니기 때문에 전역으로 취급이 됩니다. 따라서 외부에서도 접근이 가능하고, value값이 정상적으로 출력됩니다.
그 아래는 더욱 이상합니다. 마찬가지로 for 문이 종료되고, console에서 접근한 i값이 5인것은 이해가 되지만, temp에 push한 function의 return값이 5만 출력되는 것은 분명 이상해 보입니다.
이는 var가 함수 스코프이기 때문에 발생한 문제로, 다음과 같은 순서로 i에 대해 탐색하고 있기 때문입니다.
v()가 실행된 함수 내부에서 i를 탐색
-> v()안에 i가 없으므로 상위 스코프를 탐색
-> 상위 스코프인 전역 스코프를 탐색
-> i = 5 발견, 사용
때문에 i는 모두 5가 출력되는 것입니다. 이는 function 내부의 i가 i의 값을 기억하는 것이 아니라 i의 참조를 공유하고 있기 때문입니다. 이 때 i는 var로 선언되었기 때문에 반복문 내에서 새로운 스코프를 만들지 않으며 모든 함수가 동일한 i를 참조하고 있기 때문입니다.
이를 해결하기 위해서 우리는 temp에 push중인 함수를 IIFE로 만들 수도 있습니다만, 좀 더 좋은 방법이 있습니다. 바로 var로 선언된 i를 블록 스코프 변수로 만드는 것입니다.
블록 스코프
위와 같이 함수 스코프를 사용하게 되면 예기치 못한 상황을 보게 될 수도 있습니다. 이를 근본적으로 해결하기 위해서는 블록 스코프를 이용하는 것이 좋습니다.
블록 스코프는 중괄호({ })를 기준으로 생성된 스코프로, 생성된 스코프의 범위 외부나 다른 함수 내에서 접근할 수 없습니다.
{
let value = 123;
}
console.log(value) // reference errorJavascript에서는 let과 const로 선언된 변수는 블록 스코프를 가지게 됩니다. 따라서 위의 예시 코드를 let으로 선언하여 사용하게 되면
if(true){
let value = 123;
}
console.log(value); // reference error
let temp = [];
for(let i = 0; i<5; i++){
temp.push(function(){
return i;
});
}
console.log(i) // reference error
temp.forEach(v=>{
console.log(v()); // 0,1,2,3,4
})위와같은 결과를 얻을 수 있게 됩니다. 따라서 재할당이 가능한 변수에는 let을, 상수값에는 const를 사용하는 것이 추천됩니다.
참조 :
https://www.w3schools.com/js/js_scope.asp
https://developer.mozilla.org/ko/docs/Glossary/Scopet