Search
Duplicate

스코프 (scope) & 클로저(closure)

생성일
2023/02/01 08:58
태그
JS

스코프 (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의 어디서 사용될까? 참고!