프로그래머스 데브코스/CS 면접 스터디

[JavaScript] 실행컨텍스트와 this

_Woogie 2023. 1. 16. 11:26

실행 컨텍스트 (Execution Context)

실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.

즉, 실행 가능한 코드가 실제로 실행되고 관리되는 영역이라고 할 수 있다.

 

실행 컨텍스트가 활성화가 되면 다음과 같은 현상이 발생한다.

  • 호이스팅 발생
  • 외부 환경 정보를 구성
  • this 값을 설정

 

실행 컨텍스트의 구성

var x = 10;
function outer() {
	var y = 10;
    
    function inner() {
    	var z = 10;
    }
    inner();
}

outer();

다음과 같은 코드가 있을때 실행 과정을 보면

  1. 최초 자바스크립트 코드를 실행하는 순간 전역 컨텍스트가 생성
  2. outer 함수가 실행, outer에 대한 실행 컨텍스트가 생성
  3. outer안에 있는 inner함수가 실행, inner에 대한 실행 컨텍스트가 생성

이렇게 실행 컨텍스트가 생성될 때마다 콜 스택에 하나씩 쌓아올려가며 코드들을 실행하게 되고, 함수가 종료하면 해당 실행 컨텍스트를 제거하는 식으로 전체 코드를 실행한다.

출처: https://frontj.com/entry/7-Javascript%EC%9D%98-this%EC%99%80-execution-context

 

그리고 이런 실행컨텍스트를 구성할 때 생기는 것들이 있다.

  • 변수 환경 컴포넌트 (Variable Environment)
    • 현재 컨텍스트 내의 식별자(변수)들에 대한 정보
    • 외부 환경 정보
    • 선언 시점의 렉시컬 환경 컴포넌트의 스냅샷 (변경사항 반영되지 않음)
  • 렉시컬 환경 컴포넌트 (Lexical Environment)
    • 처음에는 변수 환경 컴포넌트와 같음
    • 변경 사항이 실시간 반영
  • 디스 바인딩 (This Binding)
    • 식별자가 바라봐야 할 대상 객체 (함수를 호출한 객체의 참조가 저장되는 곳)

위의 3가지 중에서 This Binding에 대해 알아보려한다.

 

Variable Environment와 Lexical Environment에 대해 자세히 알아보기

 

 

this의 정의

대부분의 객체지향 언어의 this와 다르게 자바스크립트에선 상황에 따라 this가 바라보는 대상이 달라지고, 어디서든 사용할 수 있다.

 

함수가 호출되어 실행되는 시점에 this의 값(바라보는 대상)이 결정되고, 이 this의 값은 함수가 호출 될 때 함수가 속해 있던 객체의 참조이며 실행 문맥을 구성할때 생기는 this binding이 참조하는 객체이다.

 

전역 실행 컨텍스트에서의 this는?

전역 실행 컨텍스트에서 this는 전역 객체를 참조한다. 즉, 브라우저 환경이라면 this는 window객체를 바라보게 된다.

// 브라우저 환경
console.log(this); // Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}
console.log(this === window); // true

 

함수 실행 컨텍스트에서의 this는?

함수를 실행하는 방법 중 일반 함수와 메서드에 대해 비교해보자.

두개의 가장 큰 차이는 독립성이다.

 

함수와 메서드의 차이

함수는 함수 자체로 독립적인 기능을 하고, 메서드는 자신을 호출한 대상 객체에 관한 작업을 수행한다.

function func() {
	console.log(this);
}

var obj = {
	method: func,
}

// 일반 함수로서 호출
func(); // Window

// 메서드로서 호출
obj.method(); // { method: f}
obj["method"](); // { method: f}

 

 

메서드로 함수 호출할때의 this

this의 값은 호출한 주체의 객체 정보를 가리킨다.

var obj = {
  x: 40,
  method: function () {
    return this.x;
  },
};

console.log(obj.method()); // 40

 

어떤 객체에 함수를 동적할당 한 후 호출했을 때는?

function func() {
  return this.x;
}

var obj = {
  x: 40,
};

obj.method = func;

console.log(obj.method()); // 40

즉, 어떤 함수가 객체 멤버로서 호출된 것이 중요하다.

 

TMI
자바스크립트의 함수는 일급객체이다.

1. x(함수)를 변수에 담을 수 있다.
2. x(함수)를 매개변수로 넘길 수 있다.
3. x(함수)를 함수에서 반환할 수 있다.

여기서 x를 만족할 때 이를 일급객체라고 한다. (자바스크립트 짱짱맨)

 

일반 함수 호출할때의 this

메서드와 달리 일반 함수에서는 기본적으로 전역 객체를 참조하게 된다. 즉, 브라우저 환경에서는 window객체를 바라보게 된다.

하지만 strict mode에서는 실행 컨텍스트가 생성될 때 값을 유지하기때문에 undefined로 남아있는다.

function func1() {
  console.log(this);
}

function func2() {
  'use strict';
  console.log(this);
}

func1(); // Window
func2(); // undefined

혹시 내부함수에서는 다르지 않을까?

// 예시 1
var rootObj = {
  func: function () {
    console.log(this); // {obj:{...}, func:f}

    function inner() {
      console.log(this); // Window
    }
    inner();
  },
  obj: {
    func: function () {
      console.log(this); //{func:f}
    },
  },
};

rootObj.func();
rootObj.obj.func();

// 예시 2
function f1() {
  function f2() {
    function f3() {
      console.log(this);
    }
    f3();
  }
  f2();
}
f1(); // Window

똑같이 this는 window를 가리킨다.

결론적으로 내부함수에서의 this는 window를 가리키고, 위 예시들과 같이 함수를 어떻게 호출하는지에 따라 this가 가리키는 대상이 달라지게 된다.

 

this가 현재 실행 컨텍스트에 바인딩 된 대상이 없을때, 직전 컨텍스트의 this를 바라보게 하는 방법은 없는걸까?

 

this를 우회하는 방법

변수를 활용 (ES6 전에 가장 대표적인 방법)

상위 스코프에서의 this를 변수로 저장하고 활용하면 내부 함수에서 상위 스코프의 this를 사용할 수 있다.

var rootObj = {
  func: function () {
    var self = this;
    console.log(this); // {func:f}

    function inner() {
      console.log(self); // {func:f}
    }
    inner();
  },
};

rootObj.func();

 

화살표 함수

ES6에서는 함수에서의 this가 전역객체를 바라보는 문제를 보완하기 위해 화살표 함수를 새로 도입했다.

화살표 함수는 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠지게 되어, 스코프 체인 상 가장 가까운 this를 그대로 활용할 수 있다.

var rootObj = {
  func: function () {
    var self = this;
    console.log(this); // {func:f}

    var inner = () => {
      console.log(this); // {func:f}
    };
    inner();
  },
};

rootObj.func();

 

bind, apply, call

this가 바라보는 대상을 명시적으로 지정할 수 있는 메서드 bind, apply, call을 제공한다.

 

call, apply

const obj = { name: 'Tom' };

const say = function (city) {
  console.log(`Hello, my name is ${this.name}, I live in ${city}`);
};

say('seoul'); // Hello, my name is , I live in seoul
say.call(obj, 'seoul'); // Hello, my name is Tom, I live in seoul
say.apply(obj, ['seoul']); // Hello, my name is Tom, I live in seoul

call과 apply는 함수를 호출하는 함수이다. 하지만 그냥 실행하는 것이 아니라 첫번째 인자에 this가 바라볼 객체를 넘겨주어 this를 바꾸고나서 실행한다.

 

call과 apply의 차이점은 두번째 인자가 다르다. apply는 call과 다르게 배열로 넣어주어야한다.

 

 

bind

bind함수가 call,apply와 다른 점은 함수를 실행하지 않는다는 점이다. 대신 bound함수를 리턴한다.

const obj = { name: 'Tom' };

const say = function (city) {
  console.log(`Hello, my name is ${this.name}, I live in ${city}`);
};

const boundSay = say.bind(obj);
boundSay('seoul'); // Hello, my name is Tom, I live in seoul

이제 boundSay함수는 this를 obj로 갖고 있기 때문에 나중에 재사용이 가능하다.

 

생성자 함수

new 키워드와 함께 호출되면 this는 새로 만들어질 인스턴스가 된다.

생성자 함수를 호출하면?

  1. 생성자의 prototype 프로퍼티를 참조하는 __proto__라는 프로퍼티가 있는 객체를 만든다.
  2. 미리 정의된 속성을 해당 객체(this)에 부여한다.
function Cat(name, age) {
  this.name = name;
  this.age = age;
}

var choco = new Cat('초코', 10);
var nabi = new Cat('나비', 8);

console.log(choco); // Cat {name: '초코', age: 10}
console.log(nabi); // Cat {name: '나비', age: 10}

 

 


출처

https://junilhwang.github.io/TIL/Javascript/Domain/Execution-Context/#_1-%E1%84%80%E1%85%A2%E1%84%82%E1%85%A7%E1%86%B7

 

자바스크립트 실행 컨텍스트 | 개발자 황준일

자바스크립트 실행 컨텍스트 실행 컨텍스트는 자바스크립트에서 가장 중요한 핵심 개념 중에 하나다. 이를 정확히 이해하는 것은 자바스크립트 개발자에게 매우 중요하다. 1. 개념 실행 컨텍스

junilhwang.github.io

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this

 

this - JavaScript | MDN

JavaScript에서 함수의 this 키워드는 다른 언어와 조금 다르게 동작합니다. 또한 엄격 모드와 비엄격 모드에서도 일부 차이가 있습니다.

developer.mozilla.org

https://frontj.com/entry/7-Javascript%EC%9D%98-this%EC%99%80-execution-context

 

7. Javascript의 this와 execution context

this와 execution context 자바스크립트의 혼란스러운 개념 중 하나로 this키워드에 대해 알아보도록 하겠습니다. 더불어 실행 컨텍스트(execution context)도 간단히 알아보겠습니다. 실행 컨텍스트 또한

frontj.com