화살표함수 this, 실행컨텍스트, 렉시컬환경 그리고 클로저

IvanSelah·2022년 2월 5일
0

화살표 함수(arrow function) 자신의 this 가 없습니다.
대신 화살표 함수를 둘러싸는 렉시컬 범위의 this가 사용됩니다. 때문에 현재 범위에서 존재하지 않는
this를 찾을 때, 바로 바깥 범위에서 this를 찾는다.

arrow 함수안에서의 this는 동적 바인딩이 아니라, 정적으로 arrow 함수 밖에서의 context에 의해 결정되고
그럼 obj 객체 내의 this를 말하는건데, 객체 리터럴 내부에서의 this는 그 상위의 this를 참조합니다.
(블록 레벨 스코프의 this는 존재 하지 않음)

⭕️ this는 클래스, 생성자 함수, 또는 함수 레벨에서만 존재함. 그외에는 상위 context 상의 this를 참조함.

일반 function =>
우선 가장 일반적인 방법으로 함수를 선언한 후 호출하는 경우, this는 Window 객체입니다 함수 안에서 또 함수를 선언하더라도, this는 여전히 Window입니다.

객체 또는 클래스 안에서 메소드를 실행한다면 this는 Object 자기 자신
MDN정의 : 함수를 어떤 객체의 메소드로 호출하면 this의 값은 그 객체를 사용합니다.

실행 컨텍스트(스코프 , 식별자[변수, 함수, 클래스 등의 이름] , 코드 실행 순서 관리)
=> 실행 관리
렉시컬환경에서 => 식별자, 스코프 관리
코드실행순서 => 실행 컨텍스트 스택으로 관리

전역 코드 평가
=> var 키워드 선언 전역 변수, 함수 선언문으로 정의된 전역 함수 => 전역개체 프로퍼티

순서
1. 전역 실행 컨텍스트 생성
2. 전역 렉시컬 환경 생성
~ 2.1 전역 환경 레코드 생성
~ ~ 2.1.1 객체 환경 레코드 생성
~ ~ 2.1.2 선언적 환경 레코드 생성
~ 2.2 this 바인딩
~ 2.3 외부 렉시컬 환경에 대한 참조 결정

전역 코드 실행(런타임)
=> 전역 코드가 순차적으로 실행되고 값이 할당되고 함수가 호출된다. 함수가 호출되면 순차적으로
실행되던 전역 코드의 실행을 일시 중단하고 코드 실행 순서를 번격하여 함수 내부로 진입 한다.

함수 코드 평가(함수 내부 문들을 실행하기 전에)
=> 매개변수(파라미터)와 지역변수 선언문이 먼저 실행되고,
arg객체 생성되고 this 바인딩 결정 => 지역스코프에 등록

함수 코드 실행(런타임) (지역스코프 -- 상위 전역 스코프와 연결)
매개변수와 지역 변수 값이 할당되고 console이 있다면 스코프 체인을 통해 검색한다.

const x = 1;
function foo() {
  const y = 2;
  function bar() {
    const z = 3;
    console.log(x + y + z);
  }
  bar();
}
foo();

⭕️ 핵심개념 :
자바스크립트 엔진은 먼저 전역 코드를 평가하고 전역 실행 컨텍스트를 생성한다.
=> 실행 컨텍스트 스택.push(전역 실행 컨텍스트)
=> x, foo함수는 전역 실행 컨텍스트에 등록된다.
=> 이 후 전역코드가 실행되기 시작하여 젼역변수 x 에 값이 할당되고 전역함수 foo가 호출 (코드제어권 foo)
=> foo가 호출되면 전역 코드 실행은 일시 중단되고 foo 함수 내부의 함수 코드를 평가하여 foo함수 실행 컨텍스트를 생성
=> 실행 컨텍스트 스택.push(foo 함수 실행 컨텍스트)
=> 지역 변수 y 와 중첩함수 bar가 foo 함수 실행 컨텍스트에 등록된다.
=> 이 후 foo 함수코드가 실행되기 시작하여 지역변수 y에 값이 할당되고 중첩함수 bar가 호출 (코드제어권 bar)
=> bar가 호출되면(foo함수와동일)
=> bar 함수가 종료되면
=> foo 함수로 복귀(코드제어권 foo), bar 함수 실행 켄텍스트를 실행 컨텍스트 스택(callStack)에서 pop() => 종료
=> foo 함수가 종료되면
=> 전역 코드 (코드제어권 전역), foo 함수 실행 컨텍스트를 실행 컨텍스트 스택에서 pop() => 종료
=> 더이상 실행할 전역 코드가 없으므로 전역 실행 컨텍스트도 pop()

💡 렉시컬 환경 :
식별자와 식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조(실행 컨텍스트 구성하는 컴포넌트)
💡 실행 컨텍스트 스택이 코드 순서를 관리한다면 렉시컬 환경은 스코프와 식별자를 관리한다.

각 실행컨텍스트에 각 렉시컬 환경은 바인딩된다
let, const 키워드로 선언한 전역 변수는 전역객체의 프로퍼티가 되지않고 개념적인 블록(선언적환경레코드) 내에 존재한다.
전역환경레코드 = 객체환경레코드 + 선언적환경레코드

객체환경레코드 = var, 함수선언문 등
객체환경레코드는 BindingObject라고 부르는 객체와 연결되고 전역 객체의 프로퍼티와 메서드가 된다.
그래서 식별자(window.) 없이 호출가능하다.
var로 선언한 변수는 "선언단계"와"초기화단계"가 동시에 진행되고 BindingObject를 통해 변수 식별자 키를 등록하고 암묵적으로 undefined를 바인딩한다.
그렇기 때문에 코드 평가 단계에서도 선언문이전에도 참조할 수있다.
단, 변수 선언문 이전에 참조한 변수의 값은 언제나 undefined이다. => 변수 호이스팅 발생하는 원인
함수 선언문으로 정의한 함수가 평가되면 함수이름과 동일한 이름의 식별자를 객체환경레코드에 바인딩된 BindingObject를 통해 전역객체에 ⭐️ 키로 등록하고 생성된 함수 객체를 즉시 할당한다.
=> 함수 호이스팅 발생하는 원인
즉, 함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할수 있다.(변수 호이스팅과 함수 호이스팅 차이)

선언적환경레코드 = let, const 선언한 전역 변수관리
전역객체의 프로퍼티가 되지 않으므로 window. 으로 참조할 수 없다.
또한 const 키워드로 선언한 변수는 "선언단계"와"초기화단계" 가 분리되어 진행된다.

const x = 1;
funtion foo() {
	const y = 2;
    console.log(x + y);
}

Global Lexical Environment
: x = 1
: foo = function object
foo Lexical Environment
: y = 1

함수 객체는 자신이 정의된 스코프, 즉 상위 스코프를 기억한다.
(스코프체인)
자바스크립트엔진은 함수 정의를 평가하여 함수 객체를 생성할 때 현재 실행 중인 실행 컨텍스트의 렉시컬 환경, 즉 함수의 상위 스코프를 함수 객체의 내부 슬롯에 저장한다. 그러므로 생명 주기가 종료되어도
외수 함수의 변수를 참조할 수 있다. 이러한 것을 클로저라고 한다.

profile
{IvanSelah : ["꿈꾸는", "끊임없이 노력하는", "프론트엔드 개발자"]}

0개의 댓글