책에 따르면 this는 자바스크립트에서 스코프 다음으로 중요한 내용이라고 한다.
볼 때마다 헷갈리는 개념이므로 이번 기회에 예제와 함께 확실히 정리하려 한다.
const myCar = {
color: 'red',
logColor: function() {
console.log(this.color);
},
};
myCar.logColor(); // red
이 예제에서 객체의 메서드 내부의 this는 자신이 포함된 메서드를 보유한 객체(myCar)에 자동적으로 바인딩된다.
즉, 메서드(logColor)를 호출하면 this는 자동적으로(암시적으로) myCar가 된다.
위와 달리, 만약 메서드를 바로 호출하지 않고 변수에 담아버린다면(= 한 다리를 건넌다면) 어떻게 될까?
const myCar = {
color: 'red',
logColor: function() {
console.log(this.color);
}
}
const unboundGetColor = myCar.logColor; // 호출을 하지 않고 변수에 담기만 했다
// unboundGetColor는 엄밀히 말하면 logColor의 값 부분, 즉 function() { ~ } 부분을 뜻한다.
console.log(unboundGetColor()); // this와 myCar와의 암시적 바인딩이 끊어진 상태이다
// 이때의 this가 포함된 함수는 단독 함수와 동일하다 => this가 window 전역 객체를 가리키게 된다
// window 전역 객체에는 color라는 프로퍼티가 없다 => 결과적으로 undefined 출력
const boundGetColor = unboundGetColor.bind(myCar);
// this를 '명시적으로'(개발자가 직접) myCar 객체에 바인딩시킴
console.log(boundGetColor());
// this가 myCar에 제대로 바인딩되어 myCar 객체의 color 프로퍼티 값(red)을 잘 출력하게 된다.
bind 대신 call이나 apply를 쓸 수도 있다.
bind를 쓸 경우
위의 예제처럼 bind한 내용을 따로 한번 더 실행시켜줘야 하지만
call과 apply는 그럴 필요가 없다.
function Car(maker, color) {
this.carMaker = maker;
this.carColor = color;
}
function MyCar(maker, color) {
Car.call(this, maker, color); // call은 인자를 인수의 나열로 받는다
this.age = 5;
}
const myNewCar = new MyCar('bmw', 'red');
console.log(myNewCar.carMaker); // bmw
console.log(myNewCar.carColor); // red
call에 MyCar 객체(= this)를 전달하여 Car의 this.carMaker가 MyCar의 인수로 전달한 maker로 설정되도록 했다. (color도 마찬가지)
다음은 같은 내용을 apply로 처리한 코드이다.
...
function MyCar(maker, color) {
Car.apply(this, [maker, color]); // apply는 인자를 배열로 받는다
this.age = 5;
}
...
apply는 call과 같은 역할(this의 명시적 바인딩)을 한다.
하지만 call보다 분명한 장점이 있다.
바로 함수에 필요한 인수의 수를 모르거나 알 필요가 없을 때도 사용할 수 있다는 것이다.
call은 개별적으로 인수를 전달해야 하므로 이러한 경우 사용할 수 없지만,
apply는 (args 부분을) 배열 형태로 받기 때문에 인수를 몇 개를 받아도 상관 없다.
const ourFunction = function(item, method, args) {
method.apply(args);
}
ourFunction(item, method, ['argumen1', 'argument2'];
ourFunction(item, method, ['argumen1', 'argument2', 'argument3'];
개인적으로 책에서 언급한 apply의 장점에 가독성도 추가하고 싶다.
인수가 아닌 this가 다른 인수들과 똑같이 나열되어 잘 구분되지 않는 call과 달리,
apply를 사용하면 인수들이 배열로 둘러싸여 있어서 this를 더 명확히 구분할 수 있는 것 같다.