Lexical Scope
특정 코드가 작성, 선언(정의)된 환경이며 객체
모든 함수, 코드 블록{}, 스크립트는 렉시컬 환경을 가진다
var a = 1;
function printA() {
console.log(a); // 1
}
function insertA() {
var a = 10;
printA();
}
insertA();
// 1 출력
var x = 1;
function outer() {
var x = 4;
function inner() {
console.log(x);
}
inner();
}
outer();
// 4 출력
JavaScript는 함수 단위로 Scope를 생성한다
함수가 생성되면 실행 컨텍스트(Execution Context) 가 생성된다
자신의 Scope -> 자신을 포함하는 외부 함수 Scope -> 전역 Scope 순으로 변수를 찾는다
위 코드에서
⑴ inner() 내부에서 변수를 찾는다
⑵ inner() 내부에 변수가 없으므로 Scope Chain으로 연결된 outer() 내부에서 변수를 찾는다
만약 outer()에도 변수가 없다면 전역 Scope까지 찾고 없을 경우 에러가 발생한다
=> 이렇게 Scope가 연결되어있는 것을 Scope Chain이라고 한다
*실행 컨텍스트(Execution Context)
자바스크립트 코드가 실행되고 연산되는 범위
Global Execution Context
베이스 실행 구역
코드를 실행하며 단 한 번만 정의되는 전역 Context
특정 함수 내부에서 실행되는 코드가 아니라면 코드는 전역 컨텍스트에서 실행된다
전역 컨텍스트에서는 두 가지 일이 이루어지는데 ⑴ window 오브젝트인 전역 컨텍스트를 생성하고 ⑵ this 를 global object로 할당한다
Functional Execution Context
함수가 호출(실행)될 때마다, 해당 함수에 대한 실행 컨텍스트가 생성된다
각각의 함수들은 자신만의 실행 컨텍스트를 가지지만 실행 컨텍스트는 함수가 호출이 되어야 만들어진다
전역 실행 컨텍스트가 단 한 번만 정의되는 것과 달리, 함수 실행 컨텍스트는 매 실행(호출)시마다 정의되며 함수 실행이 종료(return)되면 Call Stack에서 제거된다
Eval Function Execution Context
eval 함수로 실행한 코드의 Context
보안상 취약한 점이 있어 비권장 함수이며, JS 개발자들에게 많이 쓰이는 개념은 아니다
JS는 Lexical Scope를 사용하며 프로그래밍 언어가 구동되는 환경인 runtime에 동적으로 Scope를 정하지 않고 Compile 시점에 변수나 함수가 선언된 위치를 기준으로 Scope를 정한다
함수 내부에 선언된 함수는, 자신을 포함하는 외부 함수와 전역 Scope에 대한 Scope Chain을 가지고 있다
클로저(Closure)
사전적 의미로 폐쇄란 뜻을 가지고 있다
어떤 함수가 자신의 외부에서 선언된 변수에 접근하는 것
클로저는 함수를 렉시컬 스코프 밖에서 호출해도 함수는 자신의 렉시컬 스코프를 기억하고 접근할 수 있는 특성이다
var x = 1;
function outer(z) {
var y = 2;
return function inner() {
console.log(x + y + z);
}
}
var sum = outer(3);
sum();
// 6 출력
inner()는 outer()의 y,z를 참조하고 있는 Scope Chain을 가지고 있다
그래서 outer()가 종료되었음에도 변수 y, z는 메모리에서 해제되지 않고 inner() 내부에서 참조할 수 있다
외부 함수(outer())가 종료되었음에도 Scope Chain을 이용해 외부 함수의 변수, 인자에 접근 할 수 있는 함수
=> 클로저(Closure)
var a = 1;
function outer(d) {
var c = 2;
return function middle(c) {
var b = 3;
return function inner() {
console.log(a + b + c + d);
}
}
}
var middle = outer(4);
var inner = middle(5);
console.dir(inner);
* console.dir()
console.log는 요소를 HTML과 같은 트리 구조로 출력한다
console.dir은 요소를 JSON과 같은 트리 구조로 출력한다
[[Scopes]]에서 Scope Chain을 확인할 수 있다
Scope Chain의 첫 번째 요소는 inner()에서 가장 가까운 middle()의 변수(c, b), 인자 정보를 저장한다
두 번째 요소는 outer()의 변수(e, d), 인자를 저장하고 있다
마지막으로 Global 정보를 저장한다
Scope Chain은 내부 함수가 사용하는 정보들에 대해서만 유지한다
클로저(Closure)의 장점
Private한 변수와 함수를 사용함으로써 OOP의 캡슐화와 정보 은닉의 장점을 제공한다
또한 값을 보존한다
내부 함수에서 외부 함수의 변수나, 인자를 기억하고 있기 때문에 비동기 함수나 이벤트 핸들러의 내부에서 정상적인 값을 참조 할 수 있다
클로저(Closure)의 단점
메모리를 소모한다
=> outer(), inner() 함수의 경우 outer() 함수가 종료되었음에도 inner() 함수가 종료될 때까지 메모리에서 해지되지 않고 있기 때문이다
Scope 생성에 따른 퍼포먼스 손해가 있다
https://medium.com/sjk5766/lexical-scope-closure-%EC%A0%95%EB%A6%AC-41f5d1c928e4