실행 컨텍스트

cutiepazzipozzi·2023년 8월 13일
1

Challenge

목록 보기
4/7

실행 컨텍스트란?

= 함수를 실행하는데 필요한 환경이나 조건을 담은 객체

  • 전역 공간 생성 시, 함수 생성 시 실행 컨텍스트가 생성됨
    = 그래서 환경은 전역 공간이 될 수도, 함수 내부가 될 수도 있음
    (** 함수 = 동일한 조건이나 환경을 지니는 코드 뭉치)
  • 자바스크립트 엔진의 콜스택 안에 쌓여 선입후출의 형태로 하나씩 꺼내져 실행 (코드의 환경과 순서 보장)

세 가지 환경정보 (실행 컨텍스트가 담는)

1. Variable Environment

= 식별자의 정보를 수집

  • 값의 변화 반영 X (최초의 값만 저장)

2. Lexical Environment

= 식별자의 '데이터' 추적

  • 값의 변화 반영 O

Lexical Environment

= 어휘적 환경
= 실행 컨텍스트를 구성하는 환경 정보들을 모아 사전처럼 구성한 객체

(** 여기서 변수와 식별자가 헷갈렸는데, 변수는 변할 수 있는 값을 뜻하고 식별자는 그런 변수에 붙이는 변수명?이름을 일컫는다)

2-1. Environment Record

= 현재 문맥의 식별자 정보
(해당 컨텍스트 환경에 필요한 식별자, 식별자의 값 기록)

  • 여기서 호이스팅 개념이 탄생함
    (함수 실행보다 환경 기록 수집이 먼저 일어남)

2-2. OuterEnvironment Reference

= 현재 문맥과 관련있는 외부 식별자 정보

  • 선언된 위치의 Lexical Environment를 참조하여 존재한다면 사용하고, 없다면 이 outer environment reference를 참조하여 탐색하는 과정을 반복함
    => Scope Chain
  • variable shadowing(가린다) : 가장 가까운 (가장 먼저 찾아지는 것) 것만을 찾고 나머지는 가려짐(은닉화?)
  • 다만 본인보다 더 안쪽으로는 들어갈 수 X

3. This Binding

= 실행 컨텍스트에서의 this로 지정된 객체의 정보를 갖는 것!!

  • 컨텍스트에 해당되는 함수가 호출되는 순간, 실행 컨텍스트가 활성화될 때 this binding이 일어난다!

호출 방식에 따른 this

  • 브라우저 / node.js
  1. 전역 공간: window / global
  2. 함수 호출 시: window / global
  3. 메서드 호출 시: 메서드 호출 주체 (메서드명 앞)
parser.parse() // 요기의 parser!!!
  1. callback 호출 시: (기본) 함수 내부에서와 동일
    -> 이는 콜백함수를 넘겨받는 대상이 매개변수로 받는 것을 어떻게 처리하느냐에 따라 달라지기 때문에 그때그때 다름!! 임의로 bind함수를 걸어주면 원하는 객체가 들어가게 됨!

** 콜백함수: 회신되는 함수(= 넘기고자 하는 대상에게 제어권을 넘겨줌)
5. 생성자함수 호출 시: 인스턴스(=new 연산자)

** 메서드: 원래는 함수이나 어떤 객체와 관련된 동작을 하게 되면 메서드로 취급함

++ ES6의 arrow function 사용시

※ arrow function = () => {}로 표기되는 문법

기존의 함수는 어떤 식으로 호출했느냐에 따라 this에 바인딩할 객체가 동적으로 결정되었으나, arrow Function은 언제나 상위 스코프의 this (= Lexical this)를 가리킨다!

var name = 'sk';

var myName = {
  name: 'judy',
  getName: () => console.log(this.name),
};

myName.getName(); //sk!!!

++ 호이스팅 (=끌어올리다)

= 정보 수집 개념을 더 쉽게 이해하기 위해 만들어진 허구적인 개념
= 선언된 변수를 위로 끌어올림

  • 실행 컨텍스트가 활성화되면 발생
  • 변수는 정의부(var a)만 호이스팅 되지만, 함수는 함수 내부까지도 호이스팅됨!

근데 여기서 더 얘기해보면,, 호이스팅 시 var은 undefined로 초기화되지만, let/const는 변수를 초기화하지 않는다.

이 이유를 알기 위해서는 변수 선언 3단계를 먼저 알아야 한다.
변수는
1. 선언(실행 컨텍스트의 변수 객체에 등록)
2. 초기화(등록된 변수를 위한 공간을 메모리에 할당)
3. 할당(undefined로 초기화된 변수에 실제 값을 할당)

3단계를 거쳐서 생성이 된다.

이때 var은 변수 선언 전에 선언, 초기화 단계가 동시에 진행된다. 그러나 let은 선언과 초기화 단계가 별개로 진행되기 때문에 실행 컨텍스트에 변수를 등록하여도 메모리가 할당되지 않아 참조 에러가 발생한다.

그래서 let이 호이스팅이 발생되지 않는다고 생각할 수 있지만!!

let foo = 1; // 전역 변수

{
  console.log(foo); // ReferenceError: foo is not defined
  let foo = 2; // 지역 변수
}

let은 블록 스코프를 가지기 때문에 코드 블럭 내의 foo는 지역 변수이고 해당 스코프에서 호이스팅이 발생되고 코드 블록의 선두부터 초기화가 이루어지는 지점까지 일시적 사각지대(TDZ)에 빠진다.

PoimeWeb 인용
** 함수 스코프: 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다.
ex. var

** 블록 스코프: 모든 코드 블록(함수, if 문, for 문, while 문, try/catch 문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다.
ex. let, const

클로저

= 자신이 생성될 때의 환경을 기억하는 함수
(반환된 내부함수가 자신이 선언됐을 때의 환경인 스코프를 기억해 자신이 선언됐을 때의 환경 밖에서 호출되어도 그 환경에 접근할 수 있는 함수)
= 외부 참조를 통해 함수 종료 후에도 사라지지 않는 지역 변수를 만들 수 있는 특별한 현상

  • 함수형 프로그래밍 언어에서 사용되는 중요한 특성

간단한 예시

function outer() {
  let x = 10;
  return function increase() {
    x++;
    console.log(x);
  };
}

const inner = outer();
inner(); //11

(나와 같은) 초심자의 눈으로 보면, outer 함수의 실행이 종료될 때 지역 변수 x도 접근이 불가능하다고 생각할 수 있다. 그러나 실제로 출력은 x가 1 증가된 값인 11로 잘 출력되고 있음을 알 수 있다.

이것이 클로저의 능력이다. 반환된 increase가 자신이 선언됐을 때의 환경(lexical environment)을 기억하여 자신이 선언된 곳의 외부 환경에서 호출되어도 그 환경에 접근할 수 있게끔 만들어준다!

클로저의 이름도 위의 원리에서 파생되었다. 클로저에 의해 참조되는 외부함수의 변수 (위의 예시에선 outer의 x)를 자유변수라고 부르는데, 이 자유변수에 함수가 닫혀있다는 의미에서 클로저라고 이름짓게 되었다!

근데 클로저를 왜 사용함?

클로저가 있다면 굳이 변수를 전역으로 선언하지 않아도(은닉화) 값의 수정이 가능하기 때문이다! (전역변수는 외부에서도 접근이 매우 수월함)

클로저의 활용

  1. 상태 유지
    = 현재 상태를 기억하고 변경된 상태를 유지
  2. 전역 변수 사용 억제
    = 전역 변수를 사용하면 누구나 접근하여 변경할 수 있기 때문에 클로저를 통해 지역변수화 시킨다
  3. 정보의 은닉

그리고 생각보다 정리 잘한 과거의 나

참고

코어 자바스크립트 강의
호이스팅
TDZ
실행 컨텍스트
클로저

profile
노션에서 자라는 중 (●'◡'●)

0개의 댓글