1. 기술/웹, 자바스크립트

JavaScript - Scope와 Closer

swsong 2019. 10. 19. 01:11

ES5까지 자바스크립트에서 변수를 참조할 수 있는 유효 범위의 단위는 함수였다. 예를 들어 코드에 함수가 하나 존재한다면 함수 밖의 변수는 Global Scope, 함수 안의 변수는 Local Scope 내에서만 호출할 수 있다.

변수를 선언할 수 있는 유일한 방법은 var를 키워드를 사용하는 것인데, var는 변수의 중복과 키워드 생략을 허용한다는 점에서 의도하지 않은 결과를 나타낼 수 있다.

그리고 유효범위, 즉 스코프의 단위가 함수라는 점에서 함수 내의 for문 또는 if문에서만 필요한 변수가 함수 전역에 머물러 있기 때문에 변수 사용이 끝난 시점에도 불필요한 메모리를 낭비하게 된다.

변수를 선언할 때 'var' 키워드를 사용한다면 이때의 변수는 항상 포함된 함수 scope 혹은 Global Scope에 만들어진다. 따라서 중복해서 변수 이름이 사용될 때의 에러 발생을 사전에 방지하기 위해서라도 변수 선언에는 let, const 만 사용하는 게 좋다. 뿐만 아니라 var 키워드를 통해 변수를 선언하게 되면 호이스팅(Hoisting) 문제도 존재하는데, 호이스팅은 var 선언문이나 function 선언문을 해당 스코프의 선두에 옮긴 듯한 동작을 말한다.

먼저 변수가 생성되는 과정을 보면 선언,  초기화, 값 할당으로 이루어져 있다. 그런데 var를 사용하면 선언과 초기화가 동시에 이루어진다.

이와 달리 let, const는 초기화 단계가 변수를 선언하는 라인에서 이루어지기 때문에 그보다 앞서 호출하게 되면 참조 에러(ReferenceError)가 발생한다. 사실 자바스크립트는 let, const를 포함해 모든 선언문을 호이스팅하기 때문에 스코프가 시작됨과 동시에 선언이 이루어진다고 볼 수 있다. 다만 var는 스코프가 시작될 때 이미 해당 메모리를 확보하고 변수를 'undefined'로 초기화까지 해버리기 때문에 선언 라인 이전에 함수를 호출해도 에러가 발생하지 않는다는 점에서 차이가 있다.

현대식 자바스크립트 문법에서는 이러한 복잡성을 최소화하고 자바스크립트의 지나친 자유도를 의도적으로 막는 추세이므로 var라는 키워드는 머릿속에서 지우는 편이 좋다. 

앞서 ES5까지 스코프의 단위가 함수라고 했다. ES6부터 자바스크립트가 let, const를 지원하면서 자바스크립트가 따르는  '함수 레벨 스코프'에 추가로 '블록 레벨 스코프'에만 존재하는 변수를 선언하는 것이 가능해졌다. 이를 통해서 함수의 중복을 방지하고 메모리를 효율적으로 관리할 수 있게 되었다. 그리고 스코프와 관련해서 반드시 알아야 할 필수적인 개념이 있는데 바로 클로저(Closer)다. 자바스크립트에서는 함수가 리턴(return)되는 순간 함수가 가지고 있던 변수가 저장되어서 함수 스코프가 사라져도 변수에 접근할 수 있는데, 스코프 안에 스코프가 존재하는 형태인 스코프 체인(ScopeChain)에서 변수의 값을 보존하고 넘겨받는 개념으로 클로저라 부른다.

이를 통해 외부의 접근으로부터 값을 은닉해 보호하거나 인자 혹은 콜백 함수의 사용을 위해 잠시 필요한 함수를 일회성으로  용하는 등으로 유용하게 활용할 수 있다.