자바스크립트에서 함수는 객체이므로 call, apply, bind라는 내장 메서드를 갖는다. 이 메서드들은 함수가 실행될 때 this가 가리키는 대상을 명시적으로 지정할 수 있게 해준다. 세 메서드의 공통점과 차이점을 정리하면 다음과 같다.
- 공통점: 첫 번째 인자로
this로 사용할 컨텍스트 객체를 전달한다. 이후 인자들은 원본 함수에 전달될 값들이다. - 차이점:
call과apply는 함수를 즉시 호출하지만,bind는this가 고정된 새 함수를 반환하여 나중에 호출할 수 있게 한다. 또한call은 인자를 하나씩 나열하고,apply는 배열(또는 유사 배열 객체)로 묶어 전달한다.
call 메서드
문법: func.call(thisArg, arg1, arg2, ...)
call은 주어진 thisArg와 인자들을 사용해 함수를 즉시 실행한다. thisArg에 전달된 값에 따라 this가 결정되는 규칙은 다음과 같다.
null또는undefined를 전달하거나 생략하면 전역 객체(브라우저 환경에서는window, 엄격 모드에서는undefined)가 바인딩된다.- 원시값(문자열, 숫자, 불리언)을 전달하면 해당 원시값의 래퍼 객체(
String,Number,Boolean)로 변환된다. - 객체를 전달하면 그 객체가
this가 된다.
function greet() {
console.log(this);
}
const user = { nickname: 'coder' };
greet.call(); // 전역 객체 (또는 엄격 모드 undefined)
greet.call(null); // 전역 객체
greet.call(undefined); // 전역 객체
greet.call(42); // Number {42}
greet.call('hello'); // String {'hello'}
greet.call(true); // Boolean {true}
greet.call(user); // { nickname: 'coder' }
다른 객체의 메서드를 빌려 쓰는 패턴도 자주 등장한다. 생성자 함수 안에서 다른 생성자를 호출해 속성을 상속받는 예시다.
function Person() {
this.describe = function() {
console.log('Person의 메서드');
};
}
function Developer() {
Person.call(this); // Developer 인스턴스에서 Person의 속성을 사용 가능
}
const dev = new Developer();
dev.describe(); // 'Person의 메서드'
또한, call을 이용해 함수의 실행 문맥을 바꾸면서 임의의 인자를 전달할 수 있다.
function multiply(a, b) {
console.log(a * b);
}
function subtract(a, b) {
console.log(a - b);
}
multiply.call(subtract, 5, 3); // 15 (this는 subtract 함수지만 인자는 multiply에 전달됨)
프로토타입 기반 상속이 아닌 임시 메서드 빌려쓰기에도 유용하다.
function Vehicle() {
this.type = 'vehicle';
this.showType = function() {
console.log(this.type);
};
}
function Bike() {
this.type = 'bike';
}
const v = new Vehicle();
const b = new Bike();
v.showType.call(b); // 'bike' (showType의 this가 Bike 인스턴스를 가리킴)
apply 메서드
apply는 call과 기능이 거의 동일하지만, 인자들을 배열 형태로 전달한다는 점만 다르다. 배열이나 유사 배열 객체를 두 번째 인자로 받는다.
function sum(x, y, z) {
console.log(x + y + z);
}
sum.apply(null, [1, 2, 3]); // 6
sum.apply(null, { 0: 4, 1: 5, 2: 6, length: 3 }); // 15 (유사 배열)
bind 메서드
bind는 함수를 즉시 실행하지 않고, this와 일부 인자가 고정된 새로운 함수를 반환한다. 이벤트 핸들러나 콜백에서 특정 컨텍스트를 유지해야 할 때 주로 사용된다.
function introduce(greeting) {
console.log(greeting + ', ' + this.name);
}
const actor = { name: 'Lee' };
const boundIntroduce = introduce.bind(actor, 'Hello');
boundIntroduce(); // Hello, Lee
bind로 생성된 함수는 이후에 추가 인자를 전달할 수도 있다. 이때 고정된 인자 뒤에 새로운 인자가 붙는다.
function display(prefix, suffix) {
console.log(prefix + ' ' + this.value + ' ' + suffix);
}
const obj = { value: 'core' };
const partial = display.bind(obj, 'Start');
partial('End'); // Start core End