TIL 221201

이정익·2022년 12월 1일
0

TIL

목록 보기
24/27
post-custom-banner

12월

12월이다. 12월이라는게 실감이 안날뻔했는데 날씨가 엄청나게 추워지면서 12월임을 상기시켜줬다.
캠프 종료까지 3개월 남았다.
3개월동안 더 노력하자. 지금까지보다 조금씩만 더 하루하루 어제보다 조금만 더 노력하는걸 목표로 하자.

JS에서의 실행 컨텍스트

실행 컨텍스트(Execution Context)

실행 컨텍스트라는 말조차 몰라서 찾아보았다.

실행 가능한 코드를 형상화하고 구분하는 추상적인 개념

결론적으로 실행 가능한 코드가 실행되기 위해 필요한 환경.
실행 컨텍스트는 객체형태로 콜 스택에 저장된다.

JS는 실행 컨텍스트가 활성화될 때

  1. hoisting이 진행된다.
  2. 환경변수가 구성된다.
  3. this 바인딩이 일어난다.

실행 컨텍스트 객체 내에 담기는 정보는 다음과 같다

  1. VariableEnvironment
    a. Environment Record ( 현재 컨텍스트 내의 식별자 정보 )
    b. Outer Environment Reference ( 외부 환경 정보 )
    c. 선언 시점 LexicalEnvironment의 스냅샷
  2. LexicalEnvironment
    a. VariableEnvironment와 동일하지만, 실시간으로 반영된다.
  3. ThisBinding
    a. this 식별자가 바라볼 객체

용어가 어렵다. 용어 정리하고 넘어가자.

Variable Environment

VariableEnvironment: Identifies the Lexical Environment whose environment record holds bindings created by VariableStatements and FunctionDeclarations within this execution context.

ECMAScript 스팩에 있다.
꼬부랑글 너무 어렵다. 번역기의 도움을 받아보자.

실행 컨택스트 내부에서 외부환경이 반영된 변수 정보와 함수의 정의를 포함한 Environment Record를 가지고있는 LexicalEnvironment의 스냅샷

아래부터는 VE로 표기하자.
이정도로 이해하고 넘어가자.

Lexical Environment

VE와 동일하지만, 스냅샷이 유지되지 않고 계속해서 활용된다.

아래부터는 LE로 표기하자.

Lexical Environment

LE는 아래와 같이 구성된다

  1. Environment Record ( 현재 컨텍스트 내의 식별자 정보 )
  2. Outer Environment Reference ( 외부 환경 정보, Outer )

Environment Record

현재 context와 관련된 코드의 식별자 정보들을 context 내부의 처음부터 끝까지 순서대로 훑어가며 수집

Environment Record가 수집하는 대상

  1. 함수에 지정된 parameter
  2. 함수 자체
  3. var로 선언된 변수 식별자

여기서 hoisting이 발생되는데,
Environment Record가 수집하는 대상들은, 실행 컨텍스트가 활성화되면서 해당 코드블럭의 최상단에서 실행된다 라는 개념이다(실재로 동작한다기 보다는, 개발자들의 이해를 돕기 위해 설정된 가상의 개념)

Outer Environment Reference

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는 실행 컨텍스트가 생성될 때 this binding이 실행되며 결정된다.

전역공간에서의 this는 window(전역 객체)를 가리킨다.
method에서 this는 호출의 주체가 된다. ( document.append()의 this는 document, document.querySelector("button").addEventListener()의 this는 button )
함수에서의 this는 binding하지 않으면 window가 된다.

왜 함수에서 this는 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();
  },
};

Arrow Function

ES6에서 도입된 Arrow Function은 실행 컨텍스트를 생성할 때 this binding과정 자체가 없기 때문에 this가 초기화되지 않는다.

var obj = {
  outer: function () {
    console.log(this); // obj
    var innerFunc = () => {
      console.log(this); // obj
    };
    innerFunc();
  },
};
obj.outer();

this의 명시적 binding

  • 호출 주체인 함수를 즉시 실행하며 binding 하는 method
  1. call method
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
  1. apply method
    call method와 동일하지만, 나머지 args를 쉼표로 구분하는것이 아닌 배열로 받는다는 차이점이 있다.
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
  1. bind method
    bind를 통해 호출 방법과 관계없이 특정 this값으로 호출되는 함수를 만들 수 있다.
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
  1. 내장 method 중 this를 argument로 받는 method
    forEach, map, filter, some, every, find, findIndex, flatMap, from, forEach(Set, Map)
profile
주니어 프론트엔드 엔지니어로 한걸음 나아가는 중입니다.
post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 12월 2일

스스로를 이해시키기위해 글을 정리하시는것같아 너무 보기좋습니다
잘읽고갑니다 ㅎㅎ

답글 달기