스코프 (scope), 클로저(closure)
스코프 (유효범위)
•
변수에 접근 가능한 범위
•
전역 스코프 (Global scope) : 스크립트 전체에서 참조되는 것을 의미, 어느 곳에서든 참조 된다
•
지역 스코프 (Local scope) : 정의된 함수 내에서만 참조되는 것을 의미, 밖에서는 참조 되지 않는다
특징
•
함수 단위의 유효범위 (function-level-scope)
•
변수명 중복 허용
•
암묵적 선언 (implied globals)
•
Lexical scoping (Static scoping)
함수 스코프 (function-level scope)
•
var
•
함수 코드 블럭 내에서 선언된 변수는 함수 코드 블럭 내에서만 유효
var x = 0;
{
var x = 1;
console.log(x); // 1
}
console.log(x); // 1
let y = 0;
{
let y = 1;
console.log(y); // 1
}
console.log(y); // 0
JavaScript
복사
변수명 중복 허용
•
글로벌 영역에 변수를 선언하면, 이 변수는 어느 곳에서든지 참조할 수 있는 global scope를 갖는 전역 변수가 된다
var global = 'global';
function foo() {
var local = 'local';
console.log(global); // global
console.log(local); // local
}
foo();
console.log(global); // global
console.log(local); // Uncaught ReferenceError: local is not defined
JavaScript
복사
암묵적 전역 (implied globals)
•
명시적으로 변수앞에 var를 붙여주지 않으면 암묵적 전역변수가 된다
function foo() {
x = 1; // Throws a ReferenceError in "use strict" mode
var y = 2;
}
foo();
console.log(x); // 1
console.log(y); // ReferenceError: y is not defined
JavaScript
복사
Lexical scoping (Static scoping)
•
자바스크립트는 함수가 선언된 시점에서의 유효범위를 갖는다
var number = 1234
function printNumber() {
console.log(number);
}
function wrapper() {
number = 4321
printNumber();
}
wrapper(); // 4321
JavaScript
복사
var number = 1234
function printNumber() {
console.log(number);
}
function wrapper() {
var number = 4321
printNumber();
}
wrapper(); //1234
JavaScript
복사
•
wrapper 함수 안에서 var 키워드를 사용하자 결과가 달라진다
•
함수를 처음 선언하는 순간, 함수 내부의 변수는 자기 스코프로부터 가장 가까운 곳(상위 범위에서)있는 변수를 계속 참조하게 된다
블록 스코프
•
let, const
스코프 체인 (Scope chain)
•
새롭게 정의된 스코프는 상위의 스코프에 접근 가능하다
•
스코프 체인은 scope의 가장 내부에서 scope chain을 따라 바깥쪽으로 검색을 하게 된다
클로저 (Closure)
•
클로저는 함수가 선언된 환경의(렉시컬) 스코프를 기억하여, 함수가 스코프 밖에서 실행될 때에도, 이 스코프에 접근할 수 있게 하는 기술이다
// changeCount는 inner함수
// 객체를 리턴하고 있고 객체 안에는 increase, decrease, show와 같은 inner함수들을 저장
const counter = function() {
let count = 0;
function changeCount(number) {
count += number;
}
return {
increase: function() {
changeCount(1);
},
decrease: function() {
changeCount(-1);
},
show: function() {
alert(count);
}
}
};
// counter를 실행하면 outer함수 스코프를 기억하고 있는 클로저들이 담긴 객체를 반환
// counterClosure는 counter함수 내부에 정의된 count나 changeCount에 접근 가능
const counterClosure = counter();
counterClosure.increase(); //
counterClosure.show(); // 1
counterClosure.decrease();
counterClosure.show(); // 0
JavaScript
복사
•
내부함수는 외부함수의 지역변수에 접근할 수 있는데, 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근할 수 있다
•
이러한 매커니즘을 클로저라고 한다
정리
•
클로저는 내부함수가 외부함수의 지역변수에 접근할 수 있고, 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근할 수 있는 것이다
•
클로저는 함수가 선언된 환경(렉시컬) 스코프를 기억해 함수가 스코프 밖에서 실행될 때에도, 이 스코프에 접근할 수 있게 된다
•
React에서 함수형 컴포넌트의 상태관리를 위해서는 컴포넌트 외부에 저장된 값을 사용하여 클로저를 통해 해당 값에 접근해 상태를 비교하고 변경한다
•
useState는 컴포넌트 내부에서 값을 변경시키는 것이 아니라, 외부에 있는 값을 변경시키기 때문에 상태가 변경된 직후 컴포넌트가 가진 값은 이전의 값을 그대로 참조한다
•
각 컴포넌트의 상태 정보는 배열 형태로 저장되기 때문에 상태를 변화시키는 hook을 조건문이나 반복문 안에서 사용하면 잘못된 순서의 값을 참조하게 될 수 있다
reference
→ 클로저가 hooks의 어디서 사용될까? 참고!