실행컨텍스트는 scope, hoisting, this, function , closer 등의 동작원리를 담고있는 핵심원리입니다.
실행 컨텍스트는 실행가능한 코드를 형상화하고 구분하는 추상적인 개념 을 의미합니다. 쉽게말해 실행 가능한 코드가 실행되기 위해 필요한 환경
Javascript 해석기는 함수 혹은 스크립트를 실행하려고 할 때 새로운 Context를 만들어 냅니다.
자바스크립트 엔진은 코드를 실행하기 위해
등에 대한 정보를 알고 있어야합니다. 이것들처럼 실행에 필요한 정보를 형상화하고 구분하기 위해 자바스크립트 엔진은 실행 컨텍스트를 물리적 객체형태로 관리합니다.
var x = 'xxx';
function foo () {
var y = 'yyy';
function bar () {
var z = 'zzz';
console.log(x + y + z);
}
bar();
}
foo();
이 코드가 실행되면 실행컨텍스트 스택이 생성되고 소멸됩니다.
컨트롤(제어권)이 실행가능한 코드로 이동하면 논리적 스택구조를 가지는 새로운 실행컨텍스트 스택이 생성되고 전역코드로 컨트롤이 진입하면 전역실행컨텍스트(GEC)가 실행컨텍스트 스택에 쌓이고 애플리케이션이 종료될 때 까지 유지됩니다.
함수가 호출되면 함수 실행컨텍스트가 생성되고 직전에 실행된 코드블록의 실행컨텍스트위에 쌓이고 끝날때 해당 함수의 실행컨텍스트는 파기하고 직전의 실행컨텍스트에 컨트롤을 반환합니다.
이후 내용은 여기를 참조
여기까지 설명한 내용은 사실 ES5 이전의 개념입니다. ES5부터 실행컨텍스트는 물리적으로 다른 모양을 갖습니다.
변수객체(VO), 활성화 객체, 스코프 체인등의 개념이 LexicalEnvironment로 변경되었습니다.
ExcutionContext = {
LexicalEnvironment = [Lexical Environment],
VariableEnvironment = [Lexical Environment],
thisbinding = [Object]
}
자바스크립트 엔진은 script tag를 만나면 먼저 전역 실행컨텍스트를 만들어서 이를 실행컨텍스트 스택에 push하고 함수가 호출, 종료될 때 마다 새로운 실행 컨텍스트를 만들어서 LIFO 방식으로 push pop합니다
LexicalEnvironmnet
Component를 만듭니다VariableEnvironment
Component를 만듭니다.this
값을 결정 합니다.LexicalEnvironment = {
"Environment Record" = ,
"Outer Environment Reference" = ,
}
식별자(identifier)와 특정 변수(variable)의 맵핑을 지속적으로 트래킹하는 엔진의 내부 구조입니다. LE(Lexical Environment)는 함수, 블록문, catch절 이 평가될 때 즉 {}블록문이 있을 때 생성됩니다. (호출 될 때가 아니라 선언될 때)
렉시컬 환경은 함수 선언 및 변수(let, const)바인딩을 저장하는데 사용
Lexical Environment를 scope라고 부르는 경우가 많음
Lexical Environment는 JS 코드에서 식별자 정의를 위해 사용하는 객체로 Environment Record
와 Outer Environment Reference
를 프로퍼티로 갖습니다.
Environment Record (ER)
유효범위 내의 값에 식별자(identifier)를 매핑함
DeclarativeER : 변수 선언 및 함수 선언 저장
→ 변수 선언, 함수 선언, catch절 에서 사용되는 식별자:값 맵핑 정보를 담음 ( 실제 값 저장 )
ObjectER : with문이나 전역 환경에서 사용됨.
→ with문과 같이 식별자를 어떤 특정 객체의 A의 속성으로 취급할 때 사용, bindingObject라는 프로퍼티로 A를 가리키는 참조가 저장됨
함수의 경우 arguments
객체 포함
Outer Environment Reference (Scope chain)
Scope Chain은 ES5부터
Lexical nesting structure
등으로 표현함.
Lexical Environment와 대게 동일한 값을 갖지만 만들어진 변수 선언 및 함수 선언에 대해 바인딩을 유지함.
변수(var)바인딩만 저장
LexicalEnvironment는 코드 실행중에 실행 컨텍스트 내에서 변경될 수 있지만 VariableEnvrionment는 항상 값을 유지
이전 단계인 생성단계에서는 변수의 선언이 이뤄지고 전역 실행 컨텍스트의 this가 결정됨
그리고 실행 단계에서 변수에 값이 할당되고 코드가 실행됨.
자바스크립트에서 모든 함수는 실행될 때마다 함수 내부에(lexical environment) this라는 객체가 추가됩니다. arguments라는 유사 배열 객체와 함께 함수 내부로 암묵적으로 전달 되는 것이기 때문에 this는 함수가 호출 된 상황에 따라 그 모습을 달리합니다.
암묵적 바인딩 외에도(apply/call/bind 메서드로) 명시적으로 바인딩이 가능
요약
우선 var는 function-level scope이고 변수 선언 방식에 있어서 큰 단점을 가지고 있습니다. 변수를 한번 더 선언해도 각기 다른 값을 출력하게 되구요 이때문에 let, const가 등장했습니다.
let과 const는 재선언이 불가능하고 block level scope를 가집니다. 하지만 let은 mutable하고 const는 immutable한 차이를 가집니다.
var는 호이스팅이 일어날때 변수를 메모리 공간에 할당하고 undefined로 초기화 하지만 let const은 변수가 선언된 장소에 인터프리터가 도달할 때 값이 초기화됩니다.
하지만 const도 object가 담기면 object의 수정은 막을 수 없습니다. const에 할당된 object의 주소값은 불변이겠지만, object의 값이나 상태는 여전히 변경가능합니다. 따라서 freeze 를 사용하여 object를 수정못하게 막을 수 있습니다
값을 복사
하여 처리하기 때문에 안전합니다. 원래의 값이 보존이 된다.메모리 사용량
이 늘어난다.직접 참조
를 해서 빠릅니다.원래 값이 영향
을 받는다.호이스팅은 자바스크립트 함수가 실행되기 전에 함수안에 있는 필요한 변수값을 모두 모아서 유효범위(Lexical Environment)의 최상단에 선언
해주는 것을 의미합니다.
var과 함수선언문
에서는 호이스팅이 일어나면 var은 undefined로 초기화되고 함수선언문은 함수가 통째로 호이스팅되면서 에러를 일으키지 않습니다. 하지만 함수 표현식에서는 정상적으로 함수가 실행되지 않을 수 있습니다. 호이스팅이 일어나도 해당 변수가 함수로 인식되지 않기 때문입니다.
//ex
foo(); // Error
var foo = function(){
console.log('hi');
}
스코프의 시작지점부터 초기화 시작지점까지의 구간을 TDZ라고 합니다. TDZ 시맨틱은 선언 전에 변수에 접근하는 것을 금지합니다.
호이스팅은 var과 함수선언문에서만 일어나는 것은 아닙니다.
하지만 const 변수, let 변수, class 구문, constructor() 내부의 super(), 기본 함수 매개변수 는 TDZ의 영향을 받습니다.
javascript에서 변수는 선언, 초기화, 할당이라는 3단계에 걸쳐서 생성이됩니다.
var
변수는 선언과 초기화를 동시에 진행하여 실행컨텍스트 변수 객체에 변수를 등록하고 메모리를 undefined로 만들어 버립니다.let
, const
에서도 호이스팅은 발생하지만 선언과 초기화 단계가 분리되어 진행되기 때문에 실행컨텍스트에 변수를 등록했지만. TDZ에 의해 uninitialized
상태가 됩니다. javascript 엔진은 uninitialized
상태의 변수를 인지하긴 하지만 렉시컬 바인딩이 실행되기 전까지 엑세스할 수 없습니다.function
은 선언, 초기화, 할당 단계를 동시에 진행.클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment or 스코프)을 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다. 이를 조금 더 간단히 말하면 클로저는 자신이 생성될 때의 환경(Lexical environment)을 기억하는 함수다라고 말할 수 있겠다.
일반적으로는 스코프에서 빠져나가면 해당 스코프에서 선언한 변수는 메모리에서 제거해도 안전합니다. 그럼에도 함수를 정의해 클로저를 만들면 접근할 수 없던 것들에 접근할 방법이 생기는 부수적인 특징이 있습니다.
좀 더 정확히 말하면 클로저는
내부함수의 Lexical Environment의 Outer Lexical Environment Reference(스코프체인)가 참조하고있는 외부함수의 LE를 저장해서 자신을 포함하는 외부함수의 EC가 사라지더라도 OLER을 통해(스코프체인)을 통해 참조 가능.
자신을 포함하는 외부함수의 렉시컬환경이 소멸돼도 [[Scopes]] 프로퍼티가 가리키는 외부함수의 렉시컬환경은 소멸되지 않음 이것이 클로저
데이터 보존
클로저 함수는 외부 함수 실행이 끝나도 외부 함수 내의 변수 사용이 가능함. 특정 데이터를 스코프 안에 가둬서 사용할 수 있게하는 폐쇄성
정보 접근 제한(캡슐화)
모듈 패턴을 사용해 객체에 담아 여러개의 함수를 리턴하게 만듬.
모듈화에 유리
클로저 함수를 각각의 변수에 할당하면 각자 독립적으로 값을 사용하고 보존할 수 있음. 이를 통해 데이터와 메소드를 묶어다닐 수 있음.
폐쇄된 스코프 안의 변수가 스코프 종료와 동시에 회수되지 않음. 스코프 밖에서 언제든지 변수를 호출할 가능성이 있기 때문에 가비지컬렉터에 의해 수거되지 않음. 메모리 누수나 누적에 대한 고민이 필요함.
→ 메모리 해제하면 됨
프로미스란
렌더링최적화, SEO, 코딩컨벤션, AJAX, XMLHTTPREQUEST FETCH axios, async await
javascript 성능개선, 비동기통신, 렌더링최적화,JWT
https://reese-dev.netlify.app/javascript/execution-context/
https://www.inflearn.com/questions/64181
https://iamsjy17.github.io/javascript/2019/06/10/js33_execution_context.html