12월이다. 12월이라는게 실감이 안날뻔했는데 날씨가 엄청나게 추워지면서 12월임을 상기시켜줬다.
캠프 종료까지 3개월 남았다.
3개월동안 더 노력하자. 지금까지보다 조금씩만 더 하루하루 어제보다 조금만 더 노력하는걸 목표로 하자.
실행 컨텍스트라는 말조차 몰라서 찾아보았다.
실행 가능한 코드를 형상화하고 구분하는 추상적인 개념
결론적으로 실행 가능한 코드가 실행되기 위해 필요한 환경.
실행 컨텍스트는 객체형태로 콜 스택에 저장된다.
JS는 실행 컨텍스트가 활성화될 때
- hoisting이 진행된다.
- 환경변수가 구성된다.
- this 바인딩이 일어난다.
실행 컨텍스트 객체 내에 담기는 정보는 다음과 같다
- VariableEnvironment
a. Environment Record ( 현재 컨텍스트 내의 식별자 정보 )
b. Outer Environment Reference ( 외부 환경 정보 )
c. 선언 시점 LexicalEnvironment의 스냅샷- LexicalEnvironment
a. VariableEnvironment와 동일하지만, 실시간으로 반영된다.- ThisBinding
a. this 식별자가 바라볼 객체
용어가 어렵다. 용어 정리하고 넘어가자.
VariableEnvironment: Identifies the Lexical Environment whose environment record holds bindings created by VariableStatements and FunctionDeclarations within this execution context.
ECMAScript 스팩에 있다.
꼬부랑글 너무 어렵다. 번역기의 도움을 받아보자.
실행 컨택스트 내부에서 외부환경이 반영된 변수 정보와 함수의 정의를 포함한 Environment Record를 가지고있는 LexicalEnvironment의 스냅샷
아래부터는 VE로 표기하자.
이정도로 이해하고 넘어가자.
VE와 동일하지만, 스냅샷이 유지되지 않고 계속해서 활용된다.
아래부터는 LE로 표기하자.
LE는 아래와 같이 구성된다
현재 context와 관련된 코드의 식별자 정보들을 context 내부의 처음부터 끝까지 순서대로 훑어가며 수집
Environment Record가 수집하는 대상
- 함수에 지정된 parameter
- 함수 자체
- var로 선언된 변수 식별자
여기서 hoisting이 발생되는데,
Environment Record가 수집하는 대상들은, 실행 컨텍스트가 활성화되면서 해당 코드블럭의 최상단에서 실행된다 라는 개념이다(실재로 동작한다기 보다는, 개발자들의 이해를 돕기 위해 설정된 가상의 개념)
var a = 1;
var outer = function () {
var inner = function () {
console.log(a); // undefined
var a = 3;
};
inner();
console.log(a); // 1
};
outer();
console.log(a); // 1
위 코드와 같을 때
inner()이 실행되면, inner scope 내부에 a라는 변수 식별자가 선언되었기 때문에 Outer까지 나가지 않고 undefined를 내뿜는다.
outer()가 실행되면, outer scope 내부에 a라는 변수 식별자가 선언되어 있지 않기 때문에, 전역 컨텍스트에서 선언된 a를 outer로 참조하게 된다. 따라서 1을 실행.
즉 scope chain상 가장 먼저 발견된 식별자에게만 접근이 가능하다.
this는 실행 컨텍스트가 생성될 때 this binding이 실행되며 결정된다.
전역공간에서의 this는 window(전역 객체)를 가리킨다.
method에서 this는 호출의 주체가 된다. ( document.append()의 this는 document, document.querySelector("button").addEventListener()의 this는 button )
함수에서의 this는 binding하지 않으면 window가 된다.
함수가 실행 될 때 실행 컨텍스트가 생성되면서 this가 바인딩되면서 초기화되는 과정을 거치기 때문에...
ES6에서 나온 Arrow Function은 this binding 과정을 생략하기 때문에 this가 유지된다.
var obj1 = {
outer: function () {
console.log(this);
var innerFunc = function () {
console.log(this);
};
innerFunc(); // this -> window ( 함수로써 call되었기 때문 )
var obj2 = {
innerMethod: innerFunc,
};
obj2.innerMethod(); // this -> obj2 ( method로써 call되었기 때문 )
},
};
obj1.outer(); // this -> obj1 ( method로써 call되었기 때문 )
method 내부 함수에서의 this
var obj1 = {
outer: function () {
var self = this; // self에 this를 할당해준다... 정말 간단하게 우회가능
var innerFunc = function () {
console.log(self);
};
innerFunc();
},
};
ES6에서 도입된 Arrow Function은 실행 컨텍스트를 생성할 때 this binding과정 자체가 없기 때문에 this가 초기화되지 않는다.
var obj = {
outer: function () {
console.log(this); // obj
var innerFunc = () => {
console.log(this); // obj
};
innerFunc();
},
};
obj.outer();
var func = function (a,b,c){
console.log(this,a,b,c);
};
func(1,2,3) // window{ ... } 1 2 3
func.call({ x: 1 }, 4,5,6) // { x: 1 } 4 5 6
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
},
};
obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6
this.x = 9;
var module = {
x: 81,
getX: function () {
return this.x;
},
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX();
// 9 반환 - 함수가 전역 스코프에서 호출됐음
// module과 바인딩된 'this'가 있는 새로운 함수 생성
// 신입 프로그래머는 전역 변수 x와
// module의 속성 x를 혼동할 수 있음
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
스스로를 이해시키기위해 글을 정리하시는것같아 너무 보기좋습니다
잘읽고갑니다 ㅎㅎ