자바스크립트 call, apply, bind 메서드의 동작 원리와 활용

자바스크립트에서 함수는 객체이므로 call, apply, bind라는 내장 메서드를 갖는다. 이 메서드들은 함수가 실행될 때 this가 가리키는 대상을 명시적으로 지정할 수 있게 해준다. 세 메서드의 공통점과 차이점을 정리하면 다음과 같다.

  • 공통점: 첫 번째 인자로 this로 사용할 컨텍스트 객체를 전달한다. 이후 인자들은 원본 함수에 전달될 값들이다.
  • 차이점: callapply는 함수를 즉시 호출하지만, bindthis가 고정된 새 함수를 반환하여 나중에 호출할 수 있게 한다. 또한 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 메서드

applycall과 기능이 거의 동일하지만, 인자들을 배열 형태로 전달한다는 점만 다르다. 배열이나 유사 배열 객체를 두 번째 인자로 받는다.

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

태그: call apply BIND this Function.prototype

8월 7일 23:04에 게시됨