JavaScript 클로저(Closure)란?
JavaScript에서 모든 함수는 클로저처럼 동작합니다. 클로저란 함수가 호출될 때 자신이 선언된 스코프(범위)를 사용하는 함수를 의미합니다. 즉, 함수가 호출된 위치의 스코프가 아니라, 함수가 정의된 시점의 스코프를 기억하고 참조합니다.
다음 예제를 통해 클로저의 동작 방식을 확인해 보겠습니다.
<!DOCTYPE html>
<html>
<body>
<h2>JavaScript Closures</h2>
<script>
var p = 20;
function a() {
var p = 40;
b(function() {
alert(p);
});
}
function b(f) {
var p = 60;
f();
}
a();
</script>
</body>
</html>위 예제에서 익명 함수는 변수 p를 참조할 때, 실제로 호출된 함수 b 내부의 값(60)이 아니라, 자신이 선언된 함수 a 내부의 값(40)을 사용합니다. 이처럼 함수가 정의된 환경의 스코프를 유지하는 것이 바로 클로저의 핵심 원리입니다.
JavaScript 중첩 함수(Nested Function)란?
JavaScript 1.2부터는 함수 정의를 다른 함수 내부에 중첩하여 작성할 수 있습니다. 다만, 함수 정의는 반복문이나 조건문 안에는 위치할 수 없다는 제한이 있습니다. 이러한 제약은 function 문을 사용하는 함수 선언(function declaration)에만 적용되며, 함수 표현식에는 해당되지 않습니다.
예제
아래 예제를 실행하면 중첩 함수를 구현하는 방법을 직접 확인할 수 있습니다.
<html>
<head>
<script>
function hypotenuse(a, b) {
function square(x) {
return x * x;
}
return Math.sqrt(square(a) + square(b));
}
function secondFunction() {
var result;
result = hypotenuse(5, 4);
document.write(result);
}
</script>
</head>
<body>
<p>아래 버튼을 클릭하여 함수를 호출해 보세요.</p>
<form>
<input type="button" onclick="secondFunction()" value="함수 호출">
</form>
<p>함수 내부의 매개변수 값을 다르게 변경한 후 다시 시도해 보세요.</p>
</body>
</html>위 예제에서 hypotenuse 함수 내부에 정의된 square 함수가 중첩 함수입니다. square 함수는 외부에서 직접 접근할 수 없으며, 오직 hypotenuse 함수 내부에서만 사용됩니다. 이렇게 중첩 함수를 활용하면 불필요한 전역 스코프 오염을 막고 코드의 캡슐화를 높일 수 있습니다.
클로저와 중첩 함수의 핵심 차이
두 개념을 정리하면 다음과 같습니다.
- 중첩 함수: 단순히 함수 안에 또 다른 함수가 정의된 구조를 의미합니다.
- 클로저: 중첩 함수가 외부 함수의 변수와 스코프에 접근할 수 있게 해주는 동작 방식을 의미합니다.
즉, 중첩 함수는 코드 작성 형태에 관한 개념이고, 클로저는 그 구조가 만들어내는 스코프 체인의 특성에 관한 개념입니다. JavaScript에서는 모든 함수가 클로저로 동작하기 때문에, 중첩 함수는 자연스럽게 외부 함수의 변수를 기억하고 접근할 수 있습니다.