# 자바스크립트 클로저(Closure)
# 클로저란?
외부함수의 변수에 접근할 수 있는 내부함수.
- 스코프 체인
- 클로저 자신에 대한 접근 (자신 블럭 내에 정의된 변수)
- 외부 함수 변수에 대한 접근
- 전역변수 대한 접근
- 카일 심슨의 정의: 클로저는 함수가 속한 렉시컬 스코프를 기억하여 함수가 렉시컬 스코프 밖에서 실행될 때에도 이 스코프에 접근할 수 있게 하는 기능
# 기본 예제
function showName(firstName, lastName) {
var intro = "이름은 ";
function fullName() {
// 외부함수 변수뿐만 아니고 파라미터도 사용 가능
return intro + firstName + lastName;
}
return fullName();
}
showName("유림", "진");
$(function() {
var selections = [];
$(".yoolmoo").click(function() { // 이 클로저는 selections 변수에 접근합니다.
selections.push(this.prop("name")); // 외부 함수의 selections 변수를 갱신함
});
});
# 클로저 활용
function userID() {
var userID = 999;
return {
getID: function() {
// 갱신된 userID를 리턴
return userID;
},
setID: function(newID) {
UserID = newID;
}
}
}
var myID = userID(); // 이 때, userID 외부 함수가 리턴됨
myID.getID(); // 999
myID.setID(567);
myID.getID(); // 567
# 클로저 헷갈려라
function userID(userList) {
var i; // 외부함수의 변수가 for문에 의해 변경됨
var uniqueID = 100;
for(i=0; i<userList.length; i++) {
userList[i]["id"] = function() {
// 이 내부 익명함수 클로저는 최종 갱신된 변수 i(3)에만 접근가능하다
// 이게 실행될 시점에 i는 3이다
return uniqueID + i;
}
}
return userList;
}
var userList = [{name:"율무", id:0}, {name:"연우", id:0}, {name:"다정", id:0}];
var userIDCreated = userID(userList);
var yoolmooID = userIDCreated[0]; // 이때 내부함수 호출
console.log(yoolmooID.id); //101을 원했는데 103나옴 [103, 103, 103]
function userID(userList) {
var i; // 외부함수의 변수가 for문에 의해 변경됨
var uniqueID = 100;
for(i=0; i<userList.length; i++) {
userList[i]["id"] = function(j) {
// 이 내부 익명함수 클로저는 최종 갱신된 변수 i(3)에만 접근가능하다
// 이게 실행될 시점에 i는 3이다
return function() {
return uniqueID + j;
}() //함수 리턴 대신 즉시 실행
}(i); //i변수를 파라미터로 즉시 함수호출
}
return userList;
}
# 클로저 + React hooks
// 예제 0
function useState(initialValue) {
var _val = initialValue // _val은 useState에 의해 만들어진 지역 변수입니다.
function state() {
// state는 내부 함수이자 클로저입니다.
return _val // state()는 부모 함수에 정의된 _val을 참조합니다.
}
function setState(newVal) {
// 마찬가지
_val = newVal // _val를 노출하지 않고 _val를 변경합니다.
}
return [state, setState] // 외부에서 사용하기 위해 함수들을 노출
}
var [foo, setFoo] = useState(0) // 배열 구조분해 사용
console.log(foo()) // 0 출력 - 위에서 넘긴 initialValue
setFoo(1) // useState의 스코프 내부에 있는 _val를 변경합니다.
console.log(foo()) // 1 출력 - 동일한 호출하지만 새로운 initialValue
state()
가 클로저인 이유:- state가 밖에서
foo()
이렇게 실행되었는데도 내부의_val
을 잘 리턴하고 있다. 그 내부스코프에 있던_val
이 계속 수정되더라도 상관 없이 잘 return하고 있다.
- 사실 state함수 내부를 안 보고 밖에만 본다면 밖에서 내부변수 _val이 노출되지 않았는데 계속 수정할 수 있다는게 신기하지.
- state가 밖에서
# Refer
http://chanlee.github.io/2013/12/10/understand-javascript-closure/