this 바인딩

EenSung Kim·2021년 10월 1일
0

바인딩이란?

위키백과의 네임 바인딩 항목을 보면 바인딩이 무엇인지가 자세하게 기술되어 있습니다만, 다소 난해하게 되어있어 무엇인지 이해하기가 쉽지 않았습니다. 그 대신 모던 자바스크립트 Deep Dive 와 위키백과를 통해 얻은 지식을 나름대로 풀어서 정리해봤습니다.

변수를 예로 들어 바인딩에 대해 이해해보겠습니다. 변수를 선언한다고 할 때, 이 과정은 메모리에서 공간을 확보하는 것을 말합니다. 이 때, 변수는 이 메모리 공간의 주소와 연결되어 있는 식별자입니다. 이것을 가리켜 변수의 이름과 메모리 공간의 주소가 바인딩 되었다고 할 수 있는 것이죠.

즉, 바인딩이란 식별자와 그 식별자가 가리키는 값을 서로 연결하는 과정을 의미합니다. 이러한 맥락으로 볼 때, this 바인딩이란 this 가 무엇을 가리키는지에 대한 내용이라는 것을 알 수 있습니다.


this 바인딩

다른 언어 (C++, 자바) 와 달리 자바스크립트의 this 는 함수가 호출되는 방식에 따라 this 바인딩이 동적으로 결정된다고 합니다. 함수가 호출되는 방식에 따라서 this 가 가리키는 값이 달라진다는 것이죠.

함수의 호출 방식이 다양한 만큼 this 또한 다양하게 바인딩됩니다.

  1. 일반 함수 호출 => 전역 객체가 바인딩
  2. 메소드 호출 => 메소드를 호출한 객체가 바인딩
  3. 생성자 함수 호출 => 생성자 함수가 생성할 인스턴스가 바인딩
  4. Function.prototype.apply/call/bind 메소드에 의한 간접 호출 => 메소드에 첫번째 인수로 전달한 객체가 바인딩

깊이 공부하기를 원하시는 분들은 모던 자바스크립트 Deep Dive 22장 this 부분을 참고하시면 되겠습니다. 오늘의 블로깅에서는 2번 메소드를 호출하는 경우와 1번 일반 함수를 호출하는 경우 생기는 문제점, 그리고 이를 보완할 수 있는 화살표 함수의 this 바인딩까지만 간략히 정리해보려고 합니다.


메소드를 호출하는 경우

메소드를 호출하는 경우 메소드를 호출한 객체가 바인딩된다고 합니다. 이 때 주의해야 할 것은 메소드를 호출한 객체 라는 부분입니다. 메소드가 속해있는 객체가 아니(!)라는 점이죠.

이것은 메소드가 객체에 포함된 것이 아닌 독립적으로 존재하는 별도의 객체라는 점과도 연관되어 있습니다. 아래의 예시를 통해 조금 더 자세히 살펴보겠습니다.

const car = {
  color : 'white',
  getColor() {
    return this.color;
  }
}

car.getColor();  // 'white'

위의 예시에서 마지막의 car.getColor() 가 'white' 라는 값을 리턴하는 것은 이 메소드가 car 라는 객체 안에 있기 때문이 아니라, 이 메소드를 호출한 객체가 car 이기 때문입니다.

모던 자바스크립트 Deep Dive 에 따르면 메소드는 객체에 포함된 것이 아니라 독립적으로 존재하는 별도의 객체입니다. 위의 예시에서 getColor() 메소드는 car 라는 객체의 getColor 라는 프로퍼티와 그것이 가리키는 함수 객체가 바인딩된 것이죠. 이 함수는 독립적인 객체이기 때문에 다른 객체의 메소드로 할당하는 것도 가능합니다.

const bike = {
  color : 'black'
}

bike.getColor = car.getColor;
bike.getColor();  // 'black'

bike 라는 새로운 객체를 생성하고 getColor 라는 프로퍼티에 앞선 예시의 car 객체의 메소드를 할당했습니다. 만약 car.getColor() 가 자신이 속해있는 객체와 연결되어 있다면 'black' 이라는 값이 나올 수 없을 겁니다. 그러나 bike.getColor() 메소드를 호출하게 되면 메소드를 호출한 객체가 bike 가 되기 때문에, 함수 내부의 this 는 bike 를 가리키게 됩니다.

getColor 가 가리키는 것은 그 자체로 독립적인 함수 객체입니다. 따라서 어느 객체가 호출했는지에 따라 this 바인딩이 바뀌게 됩니다. 이것이 메소드를 호출하는 경우의 this 바인딩입니다.


일반 함수를 호출하는 경우

일반 함수를 호출하는 경우에 this 에는 전역 객체가 바인딩됩니다. 그러나 일반적으로 this 가 자기 참조 변수라는 점을 감안하면 일반 함수에서의 this 는 큰 의미를 갖지 않는다고 볼 수 있습니다.

문제는 메소드 내부에서 정의한 중첩 함수, 또는 메소드에 전달한 콜백 함수가 일반 함수로 호출될 때입니다. 이 경우에도 this 는 여전히 전역 객체와 바인딩되기 때문인데요. 외부 함수인 메소드가 가리키는 this 와 내부의 중첩 함수 또는 콜백 함수가 가리키는 this 가 서로 달라지게 되어 의도한 대로 동작이 어렵게 됩니다.

서로 다른 this 바인딩을 해결하는 여러가지 방법이 있습니다. 메소드 내부에서 새로운 객체를 선언하고 this 바인딩을 할당하는 방법, this 를 명시적으로 바인딩하는 Function.prototype.apply/call/bind 메소드의 활용, 그리고 화살표 함수를 사용한 this 바인딩입니다. 그 중에서 화살표 함수를 사용한 this 바인딩을 조금 더 다뤄보겠습니다.


화살표 함수

화살표 함수는 function 키워드 대신 => 화살표를 사용해 함수를 간략하게 정의하는 방법입니다. ES6 에서 도입된 화살표 함수의 this 는 매우 편리하게 동작한다고 하는데요. 이해하는 범위 안에서 정리해보겠습니다.

앞서 메소드 내부의 중첩 함수나 콜백 함수가 일반 함수로 호출되면 this 가 서로 다르게 동작한다는 점을 언급했었습니다. 그러나 화살표 함수는 함수 자체의 this 바인딩을 갖지 않습니다.

대신 화살표 함수는 함수 선언시 정적으로 상위 스코프의 this 를 가리킵니다. 렉시컬 스코프와 비슷하기 때문에 이를 lexical this 라고 부른다고 하는데요. 이를 통해 기존의 일반 함수가 가지는 this 의 문제점을 해결하고, 보다 더 편리하게 코드를 구성할 수 있는 것이죠.

(다만 함수가 정의되는 시점에 상위 스코프의 this 를 참조하기 때문에, 메소드를 화살표 함수로 정의해서는 안된다고 합니다. 그 외에도 화살표 함수를 사용해서는 안되는 경우에 대해서는 다음의 링크를 참고하시면 되겠습니다.)


outro

모던 자바스크립트 Deep Dive 의 저자인 이웅모 님이 운영하시는 포이에마 웹에서도 this 에 관한 부분을 살펴보실 수 있습니다. 공부하시는데 도움이 되었으면 좋겠습니다.

함수 호출 방식에 의해 결정되는 this,
화살표 함수의 this

profile
iOS 개발자로 전직하기 위해 공부 중입니다.

0개의 댓글