Lighthouse of FE biginner

[JavaScript] this 바인딩 본문

자바스크립트

[JavaScript] this 바인딩

[FE] Lighthouse 2024. 12. 10. 14:15
모던 자바스크립트 Deep Dive 스터디 6회차

 

Overview

JavaScript의 this바인딩은 다른 언어의 this 바인딩과 다르게 동작한다. 상황에 따라 다르게 동작하는 this 바인딩 이번 스터디에서 부셔본다.

 

this

this는 객체 자기 자신 혹은 전역 객체를 가르킨다. 자바스크립트의 this 바인딩은 상황에 따라서 다르게 바인딩이 된다. 렉시컬 스코프는 코드의 평가 시점에 결정되는 반면에 this 바인딩은 함수의 호출 시점(런타임)에 결정이 된다.

this 바인딩

바인딩은 식별자에 메모리 주소 값을 매핑 하는 것을 뜻한다. this 바인딩 역시 this 라는 식별자에 가르키는 객체의 주소를 매핑 하는 것 이다.

 

일반 함수에서의 this 바인딩

일반 함수에서 this는 globalThis이다. 즉 브라우저에서는 window, Node 환경에서는 global 객체를 가르킨다.

 

foo 함수를 함수 선언문으로 선언했고, foo 함수를 실행한다. foo 함수에서 this를 호출하니 global 객체가 호출된다.

 

콜백 함수의 함수 선언문

콜백 함수를 일반 함수로 호출한다면 this 바인딩은 global 객체가 된다. 아래 코드에서 foo 함수는 콜백 함수를 받아서 실행한다. 첫 번째 호출에서의 콜백 함수는 함수 선언문으로 작성된 콜백 함수고, 두 번째 호출의 콜백 함수는 화살표 함수로 작성된 콜백 함수이다.

const foo = (callback) => {
  callback();
};

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

foo(() => {
  console.log(this);
});

 

6행에서의 this는 전역 객체인 global 객체를, 10행에서는 this는 상위 스코프인 foo를 가리킨다.

 

어떤 함수라도 일반 함수 선언문으로 this를 호출하면 globalThis가 바인딩 된다.

 

메서드 호출

객체의 프로퍼티에 함수가 들어가는 경우 메서드라고 이야기한다. 객체의 메서드의 this 바인딩은 함수 선언문으로 작성 됐는가, 화살표 함수로 작성이 됐는가에 따라서 다르게 동작한다.

this.value = "global";

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

const boo = () => {
  console.log(this);
};

const obj = {
  value: "obj",
  foo,
  boo,
};

foo();
boo();
obj.foo();
obj.boo();
gangdonghui@gangdonghuiui-MacBookPro py % node test2.js
<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Getter/Setter],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Getter/Setter],
  btoa: [Getter/Setter],
  performance: [Getter/Setter],
  fetch: [AsyncFunction: fetch]
}
{ value: 'global' }
{ value: 'obj', foo: [Function: foo], boo: [Function: boo] }
{ value: 'global' }

 

17행은 함수 선언문으로 작성한 foo 함수를 호출한다. 일반 함수인 foo 함수의 this는 전역 객체로 바인딩이 됐고 전역 객체가 출력된다.

 

18행은 화살표 함수로 작성한 boo 함수를 호출한다. 화살표 함수의 this 바인딩은 상위 스코프를 가리키고 boo 함수의 상위 스코프는 전역 객체이다.

같은 전역 객체이지만 다른 모습으로 출력 되는 것은 Node.js의 console.log()전역 객체를 다르게 직렬화 하기 때문이다.

 

19행은 일반 함수 선언문으로 작성된 foo 메서드를 호출한다. foo 메서드는 this를 출력하고 foo 메서드의 this 바인딩은 객체 자신인 obj를 가리킨다.

 

20행의 boo 메서드는 화살표 함수로 작성된 obj 객체의 메서드이다. 화살표 함수에서의 this 바인딩은 상위 스코프를 가리킨다. obj 객체의 상위 스코프는 전역이기 때문에 boo 메서드에서 출력하는 this는 globalThis가 출력된다.

 

메모리의 구조를 살펴보면 다음과 같다. foo, boo 메서드는 obj 객체에 소유된 것이 아닌 각 프로퍼티가 메모리에 선언된 함수 객체의 주소를 가리키고 있다.

 

생성자 함수의 this

생성자 함수는 객체를 생성할 때 호출되는 특수한 함수이다. 생성자 함수의 this는 생성될 객체를 바인딩 한다.

function Person(name, age) {
  this.name = name;
  this.age = age;
  console.log(this);
}

const person = new Person("Lee", 20);

 

Person 함수는 생성자 함수이다. 7행에서 new 연산자를 사용해 새로운 객체를 생성하고, Person이라는 생성자 함수를 호출한다.

생성자 함수에서의 this는 생성할 객체 자신을 가리킨다고 했다. 그렇기 때문에 생성자 함수에서의 this는 person이 호출된다.

 

call, bind, apply

call, bind, apply 메서드는 함수의 프로토타입 메서드이다. 해당 메서드들을 활용하면 this에 명시적으로 바인딩을 할 수 있다.

해당 메서드를 통해 arguments를 전달할 수 있습니다. 이번 회차는 this 바인딩만을 살펴봅니다.

const argsThis = { value: "args this" };

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

foo();
foo.apply(argsThis);
foo.call(argsThis);
foo.bind(argsThis)();
gangdonghui@gangdonghuiui-MacBookPro py % node test2.js
<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Getter/Setter],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Getter/Setter],
  btoa: [Getter/Setter],
  performance: [Getter/Setter],
  fetch: [AsyncFunction: fetch]
}
{ value: 'args this' }
{ value: 'args this' }
{ value: 'args this' }

 

foo 함수를 호출할 경우 global이 출력된다. apply, call, bind를 통해 명시적으로 this로 바인딩할 객체를 전달해 해당 객체가 this로 출력되는 것을 살펴볼 수 있다.

'자바스크립트' 카테고리의 다른 글

[JavaScript] this 심화 탐구  (0) 2025.04.10
[JavaScript] 실행 컨텍스트  (2) 2024.12.15
[JavaScript] eval 메서드에 대하여  (0) 2024.12.01
[JavaScript] var 그리고 let, const  (1) 2024.11.27
[JavaScript] 스코프  (2) 2024.11.24