스코프와 클로저
1. 스코프 바인딩과 체이닝
1.1 스코프 바인딩
스코프 바인딩은 변수나 함수가 특정 스코프에 연결되는 과정을 의미합니다. 자바스크립트에서는 변수가 선언된 위치에 따라 스코프가 결정됩니다. 이를 통해 변수의 유효 범위와 접근 가능성을 정의합니다. 자바스크립트는 코드가 작성된 위치에 따르는 렉시컬 스코프(lexical scope) 를 사용합니다.
렉시컬 환경
자바스크립트 엔진은 코드를 실행할 때, 스코프마다 렉시컬 환경을 생성합니다. 렉시컬 환경을 이용해 해당 스코프 내의 모든 변수와 함수를 기록하고 관리합니다.
- 환경 레코드(Environment Record): 현재 스코프에 선언된 변수와 함수의 정보를 저장합니다.
- 외부 환경 참조(Outer Environment Reference): 상위 스코프의 렉시컬 환경을 참조합니다. 이를 통해 중첩된 함수가 외부 함수의 변수를 참조할 수 있습니다.
1.2 스코프 체이닝
스코프 체이닝은 중첩된 스코프에서 변수를 찾는 과정을 의미합니다. 자바스크립트는 렉시컬 스코프를 사용하기 때문에, 변수를 찾을 때 가장 가까운 스코프부터 시작하여 상위 스코프로 이동하며 변수를 찾습니다. 이를 통해 중첩된 함수에서 외부 함수의 변수를 참조할 수 있습니다.
function outer() {
const y = 20; // outer 함수의 지역 변수
function inner() {
const z = 30; // inner 함수의 지역 변수
console.log(x, y, z);
}
inner();
}
outer();
function outer() {
const y = 20; // outer 함수의 지역 변수
function inner() {
const z = 30; // inner 함수의 지역 변수
console.log(x, y, z);
}
inner();
}
outer();
console.log(x, y, z)
에서 x를 찾을 때, inner 함수의 렉시컬 환경에서 x를 찾습니다. x를 찾지 못하면 outer 함수의 렉시컬 환경으로 이동하여 y를 찾고, y도 없으면 전역 스코프로 이동하여 x를 찾습니다.
이게 가능한 이유는 inner 함수가 outer 함수의 렉시컬 환경을 기억하고 있기 때문입니다. inner 함수는 outer 함수의 스코프에 접근할 수 있으며, outer 함수는 전역 스코프에 접근할 수 있습니다. 따라서 inner 함수는 전역 변수 x와 outer 함수의 지역 변수 y에 접근할 수 있습니다. 이렇게 스코프가 연결되어 있는 것처럼 동작하는 구조를 스코프 체이닝이라고 합니다.
2. 클로저
2.1 클로저란?
클로저(Clousre)는 함수와 그 함수가 선언된 렉시컬 환경의 조합 을 뜻합니다. 클로저는 함수가 생성될 때의 환경을 기억하고, 그 환경에 접근할 수 있는 기능을 제공합니다. 클로저를 사용하면 내부 함수가 외부 함수의 변수에 접근할 수 있게 되어 일종의 폐쇄된 공간 안의 데이터를 안전하게 다룰 수 있습니다.
반환된 함수인 inner는 outer 함수의 렉시컬 환경을 기억하고 있으며 outerVar에 접근할 수 있습니다. outer 함수가 종료되더라도 inner 함수는 outerVar에 접근할 수 있습니다. 이는 클로저의 특징입니다.
3.2 클로저의 활용
클로저는 다양한 상황에서 유용하게 사용됩니다. 특히, 데이터 은닉, 함수의 상태 유지, 이벤트 핸들러 등에서 많이 활용됩니다.
3.2.1 데이터 은닉
클로저를 사용하면 함수 내부의 변수를 외부에서 접근할 수 없도록 숨기고, 함수 외부에서 함수 내부의 변수에 접근할 수 있도록 할 수 있습니다. count
는 외부에서 직접 접근이 불가하며 클로저를 통해 접근할 수 있습니다. 이를 통해 변수와 메서드를 private하게 은닉하고, 캡슐화할 수 있습니다.
3.2.2 모듈 패턴
클로저를 사용하여 모듈 패턴을 구현할 수 있습니다. 모듈 패턴은 데이터와 메서드를 캡슐화하여 외부에서 접근할 수 없도록 하는 패턴입니다. 이를 통해 코드의 가독성을 높이고, 유지 보수성을 향상시킬 수 있습니다.
주로 즉시 실행 함수(IIFE)와 함께 사용됩니다. IIFE는 함수를 즉시 실행하여 클로저를 생성합니다. 다음은 모듈 패턴을 사용하여 폰트 관리 모듈을 구현한 예시입니다. 이 모듈은 폰트를 변경하고 현재 폰트를 확인하는 기능을 제공합니다.
3.2.3 이벤트 핸들러
클로저를 이용하여 이벤트 핸들러에서 특정 데이터나 상태를 유지할 수 있습니다. 다음과 같이 버튼 마다 카운터를 구현할 수 있습니다. 각 버튼은 독립적인 카운터를 가지며, 클로저를 통해 카운터 값을 유지합니다.
3.2.4 쓰로틀링
쓰로틀링(Throttling)은 함수 호출의 빈도를 제어하는 기술입니다. 자주 발생하는 이벤트(예: 스크롤, 리사이즈 등)에 대해 일정 시간 간격으로 함수를 실행하도록 제한합니다. 이를 통해 성능을 최적화하고 불필요한 함수 호출을 방지할 수 있습니다.
일정 시간 동안 한 번만 함수를 실행하도록 하는 쓰로틀링을 구현해보겠습니다. 다음과 같이 throttle
함수를 작성할 수 있습니다. 외부에서 접근 불가한 timerFlag를 이용하여 일정 시간 동안 함수가 실행되지 않도록 합니다.
위와 같이 쓰로틀링을 적용하여, 버튼 클릭 이벤트가 발생하더라도 2초에 한 번만 handleClick
함수가 실행되도록 할 수 있습니다. 버튼을 빠르게 클릭해도 2초 간격으로만 함수가 실행됩니다.