유효 범위라고 부르며 변수가 어느 범위까지 참조되는지를 뜻한다. 어디서든 접근 가능한 전역 스코프(Global Scope)가 있고 해당 컨텍스트 내에서만 접근 가능한 지역 스코프(Local Scope)로 나뉜다.
다만, 여기서 var 사용하면 안되는 이유가 나온다. 아래의 그림처럼 var 를 사용하면 개발자가 예상치 못한 오류를 만들 수 있다. var 를 사용하면 호이스팅 되어 변수 선언이 함수 상단으로 올라가 버린다. 그래서 블록 내부에 새롭게 선언하더라도 블록 외부 변수 값도 같이 변하게 된다. 이런 차이가 발생하는 이유는 var 는 함수 레벨의 스코프이고 const 와 let 은 블록 레벨의 스코프이기 때문이다. 따라서 var 를 사용하는 경우 개발자가 오류를 찾기 힘들어지기 때문에 가급적 사용하지 않는 것이 좋다.
함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될 때에도 기억한 스코프에 접근할 수 있게 만드는 문법이다. 아래의 코드를 보면 함수 내부에 있는 greeting 변수는 함수가 종료된 시점에 사용이 불가능해진다. 왜냐하면 블록 스코프이기 때문에 함수가 종료되면 메모리에서 사라지기 때문이다. 하지만 makeGreeting 함수를 통해 반환된 함수를 사용해보면 greeting 변수에 접근이 가능한 것을 확인할 수가 있다. 이는 반환된 함수가 Greeting 변수를 계속 참조하고 있어 메모리에서 사라지지 않기 때문이다. 이처럼 클로저는 닫힘, 패쇄라는 뜻을 가지고 있는데 더 이상 외부에서 접근이 불가능한 영역을 클로저를 통해서 접근하는 모습이 패쇄된 모습과 유사하다고 볼 수 있다.
이런 클로저를 유용하게 사용할 수 있는 방법은 은닉화이다. 클로저를 이용하면 내부 변수와 함수를 숨길 수 있다. 아래 코드의 Counter 함수를 보면 변수와 내부 함수는 외부에서 접근이 불가능하다. 따라서 반환된 함수들로만 값을 조작할 수 있게 된다. 이런 식으로 내부 변수와 함수를 숨기면서 개발자의 실수를 줄일 수 있다.
클로저를 잘 알아야 하는 이유는 유용하게 사용하기 보단 알기 힘든 버그를 잘 수정하기 위해서이다. 예를 들어, 아래의 그림에서 보이는 출력 결과는 어떻게 될까?
출력 결과는 55555 이다. setTimeout 의 대기 시간이 끝나 콜백 함수가 실행되는 시점에는 이미 루프가 종료되어 i 가 5가 되었기 때문이다. 이런 문제를 해결할 수 있는 방법은 IIFE 를 이용하거나 let을 이용하는 방법이다. let 은 블룩 수준 스코프기 때문에 매 루프마다 클로저가 생성된다.