스코프란?
ES5까지는 함수 레벨 스코프까지 지원했다.
함수 선언식으로 만들어진 함수 내부 전체에 유효한 식별자가 되어 아래 코드 처럼 에러 없이 콘솔이 찍힌다.
// 함수 레벨 스코프
function foo() {
if(true) {
var color = "blue";
}
console.log(color); // blue
}
하지만 ES6부터는 블록 레벨의 스코프를 지원한다.
아래 코드처럼 let
, const
키워드를 통해 블록 레벨 스코프 사용이 가능하다.
function foo() {
if(true) {
let color = "blue";
console.log(color); // blue;
}
console.log(color); // ReferenceError: color is not defined
}
전역 범위에 변수가 선언된 경우 전역 변수
라고 하며 Global Scope
라고 한다.
블록 내부에 변수가 선언된 경우 지역 변수
라고 하며 Local Scope
라고 한다.
const a = 5; // Global Scope
{
const b = 3; // Local Scope
conosle.log(a,b);
// 5 3
}
console.log(a,b);
// Error
클로저란?
함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될 때에도 기억한 스코프에 접근할 수 있게 만드는 문법
자바스크립트에선 함수가 실행이 완료되어도 메모리를 바로 해제하지 않는다.
변수가 여전히 다른 함수에서 참조되고 있다면 메모리에 남겨두기 때문에 참조 가능하다.
이러한 성질 때문에 아래와 같은 코드가 실행될 수 있다.
function testFunc() {
let localVar = 2;
return function() {
console.log(`localValr = ${lcalVar}`); // testFunc 지역 변수 참조
}
}
let returnedFunc = testFunc();
returnedFunc(); // localVar = 2
이런 클로저를 유용하게 사용하는 방법 중 하나는 은닉화이다.
아래의 코드처럼 내부 변수와 함수를 숨길 수 있다.
function Counter() {
let privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function () {
changeBy(1);
},
decrement: function () {
changeBy(-1);
},
value: function() {
return privateCounter;
},
};
}
const counter = Counter();
console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1
자바와 같은 몇몇 언어들은 메소드를 프라이빗으로 선언할 수 있는 기능이 있다.
하지만 자바스크립트는 태생적으로 이런 방법이 없어서 클로저의 성질을 이용하여 프라이빗 메소드를 흉내내는 것이 가능하다고 한다. 🙄