방명록
- [JavaScript] 클로저(Closure) 정리!2023년 09월 26일 00시 38분 06초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
1. 클로저(Closure) 란?
클로저는 함수와 함수가 선언된 렉시컬 스코프(Lexical Scope) 사이의 특별한 관계를 나타내는 개념이다. 함수 내부에서 선언된 함수가 외부 함수의 변수에 접근할 수 있고, 그러한 함수를 클로저라고 한다. 클로저는 외부 함수의 변수에 대한 참조를 "닫아"(Capture)서 나중에 사용할 수 있도록 저장한다. 이로 인해 외부 함수가 종료된 이후에도 해당 변수에 접근할 수 있다.
2. 클로저와 관련한 몇 가지 개념
1) 렉시컬 스코프(Lexical Scope): JavaScript는 함수를 정의할 때 함수 내부에서 외부 스코프에 접근할 수 있도록 스코프를 정의한다. 이 스코프는 함수를 선언할 때 결정되며, 함수가 어떤 변수에 접근할 수 있는지 결정한다. 이러한 스코프 규칙을 렉시컬 스코프라고 한다. 렉시컬 스코프는 코드를 작성할 때 정적으로 결정된다.
2) 실행 컨텍스트(Execution Context): 실행 컨텍스트는 코드가 실행될 때 생성되며 현재 실행 중인 코드 블록에 대한 정보를 담고 있다. 실행 컨텍스트에는 변수, 함수, 스코프 체인 등의 정보가 포함된다.
3) 스코프 체인(Scope Chain): 실행 컨텍스트마다 해당 컨텍스트의 변수와 외부 컨텍스트(상위 스코프)에 대한 참조를 가지고 있다. 이것이 스코프 체인이며, 변수를 검색할 때 사용된다. 스코프 체인을 통해 렉시컬 스코프가 구현된다.
3. 실행 컨텍스트와 스코프 체인에 의한 동적 스코프 조작과 클로저
- 렉시컬 스코프는 함수를 정의할 때 결정된다. 이것은 함수가 어떤 스코프에 접근할 수 있는지를 정의하는 데 사용된다.
- 실행 컨텍스트와 스코프 체인은 런타임 중에 생성된다. 코드가 실행될 때마다 실행 컨텍스트가 생성되고, 해당 컨텍스트의 스코프 체인이 형성된다.
- 이러한 동적 스코프 체인은 함수가 런타임 중에 동적으로 다른 스코프에 접근할 수 있는 유연성을 제공한다.
- 예를 들어, 함수가 다른 함수 내부에서 실행될 때 해당 함수의 스코프에 접근할 수 있게 된다.
- 이러한 동적 스코프 체인은 함수가 다른 함수 내에서 동작할 때 필요한 변수 및 데이터에 접근할 수 있도록 한다. 이것은 클로저가 가능한 이유 중 하나이다.
- 따라서 JavaScript는 함수의 스코프를 정적으로 결정하지만, 실행 컨텍스트와 스코프 체인을 통해 런타임 중에 동적으로 스코프를 조작할 수 있다.
- 이것은 렉시컬 스코프와 동적 스코프 체인을 혼합하여 언어의 유연성을 제공하며, 클로저와 같은 고급 기능을 가능하게 한다.
4. 클로저 예제
4.1. 예제 1
function outer() { let i = 0; function inner(x) { i += x; return i; } return inner; } // a와 b는 독립적으로 존재한다! const a = outer(); const b = outer(); console.log("a: ", a(1)); // a: 1 console.log("b: ", b(10)); // b: 10 console.log("a: ", a(1)); // a: 2 console.log("b: ", b(10)); // b: 20
4.2. 예제 2 : setTimeout()
// 1초 후 10 출력 var i; for (i = 0; i < 10; i++) { setTimeout(() => console.log(i), 1000); } // 1초 후 0~9까지 출력 var i; for (i = 0; i < 10; i++) { ((j) => setTimeout(() => console.log(j), 1000))(i); } // 1초 후 0~9까지 출력 // let 키워드 사용시 즉시 실행함수를 적용하지 않아도 0~9 출력하고 있음 for (let i = 0; i < 10; i++) { setTimeout(function () { console.log(i); }, 1000); } // 1초 후 0~9까지 출력 var i; for (i = 0; i < 10; i++) { (function (j) { setTimeout(function () { console.log(j); }, 1000); })(i); }
4.3. 예제 3 : 클로저로 인해 정상 작동하지 않는 코드와 개선된 코드
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <p id="help">Helpful notes will appear here</p> <p>E-mail: <input type="text" id="email" name="email"></p> <p>Name: <input type="text" id="name" name="name"></p> <p>Age: <input type="text" id="age" name="age"></p> <script> // 참고: https://jake-seo-dev.tistory.com/182 function showHelp(help) { document.getElementById('help').innerHTML = help; } function setupHelp() { var helpText = [ { 'id': 'email', 'help': 'Your e-mail address' }, { 'id': 'name', 'help': 'Your full name' }, { 'id': 'age', 'help': 'Your age (you must be over 16)' } ]; // 1. 클로저로 인해 정상 작동하지 않는 코드 for (var i = 0; i < helpText.length; i++) { var item = helpText[i]; document.getElementById(item.id).onfocus = function () { showHelp(item.help); }; // 익명 함수 자체가 할당 되고 있음 } // 2. 정상 작동하는 개선된 코드 // 1) 즉시 실행 함수 // for (var i = 0; i < helpText.length; i++) { // var item = helpText[i]; // document.getElementById(item.id).onfocus = ( // function (txt) { // return function () { // return showHelp(txt); // } // })(item.help) // 즉시 실행 함수로 "리턴 값 할당" // } // 2) 즉시 실행 함수(화살표 함수) // for (var i = 0; i < helpText.length; i++) { // var item = helpText[i]; // document.getElementById(item.id).onfocus = ((txt) => () => { // showHelp(txt); // })(item.help); // 즉시 실행 함수로 "리턴 값 할당" // } // 3) result 함수 호출 // for (var i = 0; i < helpText.length; i++) { // var item = helpText[i]; // document.getElementById(item.id).onfocus = result(item.help) // result함수 리턴 값을 할당 // } // function result(txt) { // return function () { // return showHelp(txt); // } // } } setupHelp(); </script> </body> </html>
참고 자료
https://jake-seo-dev.tistory.com/182728x90반응형'언어·프레임워크 > JavaScript' 카테고리의 다른 글
[JavaScript] base64 데이터를 다룰 때 만난 TypeError 에러, base64를 Blob로 변환하여 해결! (0) 2023.10.20 [JavaScript] 클린코드 자바스크립트 : 배열 (1) 2023.10.14 [Javascript] 즉시 실행 함수를 이용한 유튜브 동영상 재생 속도 제어 (0) 2023.09.22 [JavaScript] "라이트 모드-다크 모드" 전환 기능 구현 중 만난 문제, 'false'는 과연 false일까? (0) 2023.09.20 [JavaScript] 날짜 데이터를 yyyy-MM-dd 형식으로 만들기 (0) 2023.05.25 다음글이 없습니다.이전글이 없습니다.댓글