자바스크립트의 함수는 호출 이후 내부 로직을 다 실행하고 나면 다시 호출되기 전까지 작동하지 않는다.
실행 컨텍스트 편에서도 봤듯, 콜 스택에 쌓이고 실행되면 제거되기에 다시 호출한다고 해도
함수 내부의 로직을 동일하게 실행하고 다시 사라지게 된다.
function sum (addNum) {
let result = 0;
result = result + addNum;
console.log(result);
}
sum(5) // 5
sum(7) // 7
sum(10) // 10
예를 들어 위와 같은 코드에서, sum이라는 함수를 3번 호출하면 그대로 5,7,10이 반환된다.
왜냐하면 sum 함수 내부에 변수를 선언하고 그 값에 인자로 넣어준 값을 더한 다음에 반환하는데
result 변수가 함수 호출마다 0으로 초기화되기에 값은 인자 값 그대로 반환되는 것이다.
내가 하고 싶었던 건 sum 함수의 인자에 숫자를 넣으면, 계산기에 덧셈을 하는 것처럼
숫자가 점차 쌓여가는 기능을 구현하고 싶었다.
여러 가지 방법이 있겠지만, 이번에 함께 공부해 볼 클로저를 통해서도 위의 기능을 구현해 볼 수 있다.
클로저란? (Closure)
클로저를 조금 더 명확하게 이해하기 위해서는 스코프와 실행 컨텍스트에 대한 개념이
어느 정도 자리 잡고 있는 게 좋은데, 글 맨 아래 스코프와 실행 컨텍스트에 대한 정리 글 링크를 달았으니
두 개념에 대해서 모르거나 이해가 덜 됐다면 글들을 한번 읽고 오자!
클로저를 단어 그대로 해석하면 폐쇄라는 뜻이다.
자바스크립트의 함수와 연관 지어서 생각해 보면 스코프와 연관이 있을 것 같다.
자바스크립트는 함수 스코프를 따르기 때문에 함수 내부에서 선언된 변수를 함수 밖에서 접근할 수 없는데
이러한 함수의 폐쇄성과 클로저의 의미가 어느 정도 연관 되어 있다고 볼 수 있겠다.
자바스크립트에서 클로저는 함수와 함수가 선언된 렉시컬 환경의 조합이라고 말한다.
조금 더 쉽게 얘기하면 클로저는 함수 그 자체와, 함수가 선언될 당시 주변 환경의 조합이다.
주변 환경이라고 하는 것은 실행 컨텍스트에 담긴 외부 환경을 의미하는 것 같다.
정리하면, 함수와 함수가 선언될 때 외부 환경의 조합이 클로저라는 것인데,
이렇게만 보면 도무지 이해가 안 되니 조금 더 세부적으로 클로저를 파헤쳐보자.
function outerFunction() {
let outerVariable = "I am outside!";
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const myClosure = outerFunction();
myClosure();
위의 코드는 gpt가 짜준 클로저의 예시다.
outerFunction 함수 내부에는 outerVariable이라는 변수와 innerFunction이라는 함수가 있다.
그 후 반환값으로 innerFunction을 반환하고 해당 함수는 종료된다.
함수 밖에서는 myClosure라는 변수에 outerFunction 함수의 반환값을 할당하는데,
outerFunction 함수의 반환값이 함수기 때문에 myClosure도 함수가 돼서 호출할 수 있게 된다.
그래서 myClosure 함수를 호출하면 결과값으로 "I am outside!"라는 메시지가 출력되게 된다.
원래 처음 알고 있던 개념이라고 한다면 함수 내부에 있는 변수는 함수 밖에서 접근이 되지 않는다고 알고 있다.
그러나 위의 예시 코드에서는 함수 밖에서 함수를 호출했는데, 함수 내부에 있는 변수의 값이 출력됐다.
이것이 클로저가 가지고 있는 특징이 되겠다.
다시 클로저의 정의를 생각해 보면 함수가 선언될 당시 주변 환경의 조합이다라는 얘기가 있다.
다시 예시코드를 보면, innerFunction의 외부 환경은 outerFunction 함수 내부가 된다.
그래서 outerFunction에 있는 outerVariable에 접근할 수 있는 상태인데,
outerFunction의 반환값으로 innerFunction을 반환할 때
outerFunction 내부에 접근할 수 있는 환경까지 함께 반환하게 된 것이다.
그래서 outerFunction 함수의 실행이 끝나더라도 outerFunction 내부 변수 접근이 가능해지게 된다.
클로저의 특징
클로저가 가지고 있는 다양한 특징들이 있는데 이러한 특징들은 한 가지 중요한 개념에 뿌리를 둔다고 생각한다.
바로 함수 내부에서 선언된 변수는 함수 밖에서 접근할 수 없다는 함수의 특징이다.
해당 변수의 접근은 해당 함수의 호출이나 반환된 내부 함수의 호출을 통해서만 이뤄지기에
클로저는 다음과 같은 특징을 지니게 된다.
데이터 캡슐화
데이터 캡슐화라는 말은 데이터를 외부로부터 보호하여 데이터의 무결성을 유지하는 것을 의미한다.
즉, 클로저 내부에 있는 변수는 반환된 내부 함수에 의해서만 접근, 수정이 가능하고
그 외의 방법으로는 접근이나 수정, 삭제가 불가능하도록 설정되어 데이터가 안전하게 지켜질 수 있다.
function timer() {
let second = 0;
function start() {
second += 1;
console.log(second);
}
return start;
}
let addSecond = timer();
addSecond(); // 1
second += 200; // error
위의 예시를 통해 캡슐화에 대해 확인해 보면,
timer 내부에서 선언된 second라는 변수를 내부 함수인 start을 통해 값을 변경할 수 있지만,
외부에서 해당 변수의 값을 직접 수정하려고 할 때는 해당 변수를 찾을 수 없다는 에러 메시지를 띄우게 된다.
이렇게 캡슐화된 데이터는 무결성을 유지할 수 있다.
데이터 모듈화
데이터 모듈화라는 말은 큰 프로그램을 작고 독립적인 부분으로 나누어 관리하는 것을 의미한다.
이를 통해 큰 규모의 함수를 기능별로 나누어서 관리해 유지보수에도 용이해지고,
각각의 다른 기능에서 공통으로 사용되는 함수가 있다면 클로저를 활용한 모듈화를 통해 재사용도 가능해지게 된다.
function calAge() {
let age = 0;
function setAge(num) {
age += num;
console.log(age);
}
return setAge;
}
let adult = calAge();
let child = calAge();
adult(20); // 20
child(10); // 10
위의 예시를 통해 모듈화에 대해 확인해 보면,
calAge 내부에서 선언된 age라는 변수를 내부 함수인 setAge를 통해 인자에 값을 전달할 경우
age 변수의 값이 변경되도록 구현이 되어있다.
이러한 로직을 하나의 모듈로 설정하고, adult라는 변수와 child라는 변수에 각각 calAge를 호출한 반환값을 할당했다.
이렇게 되면 동일한 로직이라고 하더라도, 각 함수는 독립적인 변수에 접근해 해당 데이터를 변경할 수 있게 된다.
데이터 보존
참조하고 있는 변수의 값이 변경 이후에도 초기화되지 않고 유지되기 때문에
아래 예시와 같은 기능을 구현할 수 있다.
function calculator() {
let value = 0;
function addValue(num) {
value += num;
console.log(value);
}
return addValue;
}
const add = calculator();
add(3); // 3
add(5); // 8
add(10); // 18
위의 예시는 계산기능을 구현할 때 유용할 수 있는 로직인데, 클로저의 개념을 이용했다.
클로저를 통해 만들어진 add 함수에 인자로 다양한 값을 전달하고 여러 번 그 함수를 호출했을 경우
값이 초기화되지 않고, 이전 데이터가 유지된 채 해당 값이 변하는 것을 볼 수 있다.
이러한 클로저의 특징을 콜백 함수, 고차 함수, 모듈 패턴 등 다양한 곳에서 이용하고 있는데,
React의 가장 큰 특징 중 하나인 State도 이 클로저의 개념을 이용한 기능이기에
프론트엔드 개발자라면 클로저에 대해서 잘 알아 두는 게 좋겠다.
함께 읽으면 좋은 글 리스트
실행 컨텍스트 : 자 이게 너가 사용할 수 있는 친구들이야
포스팅 작성에 참고한 감사한 글들
Janet님 블로그 : 클로저의 개념, 특징, 장점, 예시
'Stack > JS' 카테고리의 다른 글
데이터 타입 | 기본형과 참조형 : 코어 자바스크립트 씹뜯맛즐 하기 (2) | 2024.11.20 |
---|---|
This : 이거라며.. 왜 다르냐고 (1) | 2024.11.15 |
호이스팅 (Hoisting) : 변수, 함수 끌어~ 올려! (9) | 2024.11.09 |
실행 컨텍스트 : 자 이게 너가 사용할 수 있는 친구들이야 (6) | 2024.11.08 |
Scope : 변수, 너에게 닿을 수 있는 그 범위 (1) | 2024.11.02 |