profile image

L o a d i n g . . .

var x = 1;
const y = 2;

function foo(a) {
    var x = 3;
    const y = 4;

    function bar(b) {
        const z = 5;
        console.log(a + b + x + y + z);
    };
    bar(10);
}
foo(20);
실행 컨텍스트 : 소스코드를 실행하기 위해 필요한 환경을 제공하고 코드의 실행결과를 실제로 관리하는 영역

42까지의 과정을 생각해보자.

전역환경 레코드는 객체환경 레코드와 선언적 환경 레코드로 구성되어있다.

객체 환경레코드는 기존의 전역 객체가 관리하던 var 키워드로 선언한 전역변수와 함수 선언문으로 정의한 전역함수, 빌트인 전역 프로퍼티와 빌트인 전역함수, 표준 빌트인 객체를 관리한다.
객체 환경 레코드는 BindingObject라고 부르는 객체와 연결된다.
BindingObject는 전역객체 생성에서 생성된 전역객체다.

전역 코드 평가 과정에서 var 키워드로 선언한 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 환경 레코드의 객체 환경 레코드에 연결된 .BindingObject를 통해 전역 객체의 프로퍼티와 메서드가 된다.
>> 전역 코드 평가 시점에 객체 환경레코드에 바인딩된 BindingObject를 통해 전역 객체에 변수 식별자를 키로 등록한다음 암묵적으로 undefined를 바인딩한다. 따라서 var 키워드로 선언한 변수는 코드 실행 단계에서 변수 선언문 이전에도 참조할 수 있다. 단, 변수 선언문 이전에 참조한 변수의 값은 언제나 undefined며 var 키워드로 선언한 변수에 할당한 함수표현식도 이와 동일하게 동작한다. 이것이 변수 호이스팅이 발생하는 원인이다

함수 선언문으로 정의한 함수가 평가되면 함수 이름과 동일한 이름의 식별자를 객체 환경 레코드에 바인딩된 BindingObject를 통해 전역 객체에 키로 등록하고 생성된 함수 객체를 즉시 할당한다. 이것이 변수호이스팅과 함수 호이스팅의 차이다. 즉, 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있다.


선언적 환경 레코드는 let, const 키워드로 선언한 전역 변수를 관리한다.

let x = 1;
if (true) {
    let x = 10;
    console.log(x);
}
console.log(x);

let, const키워드로 선언한 전역변수는 전역 객체의 프로퍼티가 되지않고 개념적인 블록 내에 존재하는데 이 블록이 바로 전역 환경 레코드의 선언적 환경 레코드이다.
>> 전역 객체의 프로퍼티가 되지 않기 때문에 window. 같이 전역 객체의 프로퍼티로서 참조할 수 없다.
또한 선언과 초기화 단계가 분리되어 진행하기때문에 런타임 실행흐름이 변수 선언문에 도달하기 전까지 TDZ에 빠지게 된다. (ReferenceError: Cannot access 'xxx' before initialization 발생)

this 바인딩
전역 환경 레코드의 [[GlobalThisValue]]내부 슬롯에 this가 바인딩된다. 전역 코드에서 this를 참조하면 일반적으로 전역코드에서는 전역객체를 가리키므로 [[GlobalThisValue]] 내부슬롯에 바인딩 되어있는 객체가 반환된다.
>> 참고로 전역 환경 레코드를 구성하는 객체 환경 레코드와 선언적 환경 레코드에는 this 바인딩이 없다. this 바인딩은 전역환경 레코드와 함수환경 레코드에만 존재한다

식별자 결정
동일한 이름의 식별자가 다른 스코프에 여러개 존재할 때, 어느 스코프의 식별자를 참조할 지 결정.
JS는 함수를 어디서 호출했는지가 아닌 어디서 정의했는지에따라 상위 스코프를 결정하며, 함수 객체는 자신이 정의된 스코프(상위스코프)를 기억한다.
>> 식별자를 검색할때는 언제나 실행중인 컨텍스트에서 식별자를 검색하기 시작한다. 만약 실행중인 실행컨텍스트의 렉시컬환경에서 식별자를 검색할 수 없으면 외부 렉시컬 환경에 대한 참조가 가리키는 렉시컬환경, 즉 상위 스코프로 이동하여 식벌자를 검색한다 (스코프 체인 동작원리)



식별자 검색, 렉시컬, 스코프체인, 프로토타입체인 등. system.out.println으로 생각하면서 console.log를 대입하니까 훨씬 편해졌다.
차이점이라면 BindingObject를 통하고, 참조의 참조로 이어지는 렉시컬 환경의 연속이라는 점.

코드 실행이 종료되면 객체를 포함한 모든 값은 누군가에 의해 참조되지 않을 때 가비지컬렉터에 의해 메모리 공간의 확보가 해제되어 소멸한다. 그러나 실행컨텍스트가 소멸되었다 하더라도 만약 렉시컬환경을 누군가 참조하고 있다면 렉시컬 환경은 소멸하지 않는다.


이제 난해하기로 유명한 클로저...를 공붛해야지 응ㅎ멓ㅎㅎ엏ㄴㅇㅎ



참고 :
- 모던자바스크립트 Deep Dive (이웅모), 위키북스

반응형
복사했습니다!