this... 니 와 그라노?

Plato·2022년 7월 24일
0

TL;DR: 화살표 함수의 this는 lexically bound되고, call/apply/bind를 통해 this가 참조할 객체를 지정해줄 수 없다. 화살표 함수가 아닌, 함수 표현식과 함수 선언식으로 함수를 정의해주면, 함수가 호출되는 방법에 따라 다르게 결정된다. 또한, call/apply/bind를 통해 this 키워드가 어떤 데이터를 참조할지, 지정해줄 수 있다.

서론

자바스크립트는, 일반적인 개발자의 기대/직관과 다르게 작동하는 것으로 잘 알려져 있다. 그중에서 this 키워드는, 강제 형 변환과 함께, 자바스크립트의 이해를 어렵게 만드는 주요 요인으로 꼽히곤 한다. this 키워드가 무엇을 참조할지 결정하는 방법을 알아보자.

화살표 함수에서의 this

화살표 함수는 ES6에서 도입된, 익명 함수를 정의하는 방법의 하나다. 화살표 함수에서 this는 lexically bound된다. 즉, 해당 함수의 lexical environment의 this를 참조한다. 또한 이 글의 뒤에 나오게 될 call, apply, bind 함수를 통해, this 키워드가 무엇을 참조할지 결정해줄 수 없다.
유의해야 할 점은, lexically bound되기 때문에, 상속받은 메소드를 호출할 때, 기대와 다르게 작동할 수 있다는 것.

const prototype = Object.create(null)
prototype.printName = () => {
    console.log(this.name) // 전역 공간에서 this는 전역 객체를 참조한다.
  						   // printName은 전역 공간에 있고 화살표 함수로 정의했기에, this가 전역 객체를 참조한다.
}
const childObj = Object.create(prototype) // childObj는 prototype의 메소드와 프로퍼티들을 상속받는다.
childObj.name = 'Bennito'
childObj.printName() // 기대와는 다르게 'Bennito'가 프린트되지 않고, 에러가 발생하거나, undefined를 프린트한다.
					 // 몇몇 자바스크립트 실행 환경의 경우, 전역 공간에서 this가 undefined를 참조한다. 이 경우, 에러를 발생한다.
					 // 브라우저의 경우, 전역 공간에서 this가 window를 참조한다. 하지만, window는 name 프로퍼티가 없어서, undefined를 프린트한다.

화살표 함수가 아닌 함수에서의 this

이 경우에 this의 바인딩은, 해당 함수를 어떻게 호출했느냐에 따라 달라진다.

call, bind, apply를 사용하여 호출한 경우

this가 첫 번째 argument를 참조한다.
이때, bind의 경우, 함수를 호출하지 않고 새 함수를 반환한다. bind가 반환한 새 함수의 this는, bind를 호출할 때 넣었던 첫 번째 argument를 참조한다.

메소드로 호출한 경우

어느 객체의 메소드로 호출된 것인지에 따라, this가 참조하는 객체가 달라진다. '객체_이름.메소드_이름()'와 같이 호출했다면, '객체_이름' 객체를 참조한다. 이 덕분에, 객체의 프로토타입의 메소드를 실행할 때, this 키워드가 엉뚱하게 작동하지 않는다.

const prototype = Object.create(null)
prototype.printName = function() {
    console.log(this.name)
}
const childObj = Object.create(prototype)
childObj.name = 'Bennito'
childObj.printName() // printName 함수의 this 키워드는, 전역 객체가 아니라, childObj를 참조한다.

일반 함수로 호출한 경우

이 경우, 전역 객체를 참조한다.

다른 함수의 argument로 전달하여, 콜백함수로 호출한 경우

콜백 함수 'callback'을, 고차 함수 'caller'의 argument로 전달하여 호출한 상황을 가정하자.
이때, 'callback'함수 안의 this 키워드는 전역 객체를 참조한다.
물론, 고차 함수 'caller'가, bind/apply/call을 통해, 콜백 함수 안의 this에 영향을 줄 수 있다. 이때, 콜백 함수가 화살표 함수로 정의됐다면, 이전에 말했듯이, bind/apply/call의 사용이, 콜백 함수 안의 this에 영향을 주지 않는다.

생성자 함수로 호출한 경우

함수를 호출할 때, new 키워드를 사용하면, 생성자 함수로 호출할 수 있다.
생성자 함수가 생성하는 객체를, this 키워드가 참조한다.
이때 bind를 사용하여, 해당 함수의 this가 참조하는 객체를 바꿔도, 생성자 함수의 this에 영향을 주지 않는다. 생성자 함수로 사용되면, 무조건 생성자 함수가 생성하는 객체를 참조한다.

마무리

자바스크립트는, 예상과 다르게 작동하여, 사람을 힘들게 만들 때도 있다. this가 예상대로 작동하지 않을 때, 화살표 함수로 정의했는지, 그리고 어떤 함수로 사용됐는지, 차근차근 살펴본다면, this가 무엇을 참조하는지 추론할 수 있다.

0개의 댓글