Function.prototype.call() 메서드

Function.prototype.call() 메서드

call()Function 인스턴스의 메서드로, 지정된 this 값과 개별적으로 제공된 인자들을 사용해 해당 함수를 호출합니다. 함수를 객체의 프로퍼티로 먼저 붙이지 않고도 기존 함수의 this를 임의의 값으로 지정해 호출할 수 있어, 한 객체의 메서드를 범용 유틸리티 함수처럼 재사용할 때 유용합니다.

출처: Function.prototype.call() - MDN Web Docs

본문

개요

call() 메서드는 주어진 this 값과 개별적으로 제공된 인자들을 사용해 이 함수를 호출합니다. 하나의 객체를 다른 객체의 생성자/메서드에 빌려쓰는 "메서드 빌려오기(method borrowing)" 패턴의 핵심입니다.

기본적인 사용 예는 다음과 같습니다.

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = "food";
}

console.log(new Food("cheese", 5).name);
// Expected output: "cheese"

구문(Syntax)

call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, arg2, /* …, */ argN)

매개변수

  • thisArgfunc를 호출할 때 this로 사용할 값입니다. 함수가 strict mode가 아니면 nullundefined는 전역 객체로 치환되고, 원시 값은 객체로 변환됩니다.
  • arg1, …, argN (선택) — 함수에 전달할 인자들입니다.

반환값 — 지정된 this 값과 인자들로 함수를 호출한 결과입니다.

설명(Description)

참고: 이 함수는 함수 인자를 개별 리스트로 call()에 전달한다는 점을 제외하면 apply()와 거의 동일합니다. apply()에서는 인자들이 배열 같은 하나의 객체로 묶여 전달됩니다. 예를 들어 func.call(this, "eat", "bananas")func.apply(this, ["eat", "bananas"])와 대응됩니다.

일반적으로 함수를 호출할 때 함수 내부의 this 값은 해당 함수가 접근된 객체입니다. call()을 사용하면 함수를 먼저 객체의 프로퍼티로 붙일 필요 없이, 기존 함수를 호출할 때 this로 임의의 값을 지정할 수 있습니다. 이로써 한 객체의 메서드를 범용 유틸리티 함수로 사용할 수 있게 됩니다.

경고: 생성자 체이닝(예: 상속 구현)에 call()을 사용하지 마십시오. 이는 생성자 함수를 일반 함수로 호출하게 되어 new.targetundefined가 되고, 클래스는 new 없이는 호출할 수 없으므로 오류를 던집니다. 대신 Reflect.construct()extends를 사용하십시오.

예제

call()로 함수를 호출하면서 this 값 지정하기 — 아래 예에서 greetobj의 메서드가 아님에도 불구하고 greet를 호출하면 this의 값이 객체 obj에 바인딩됩니다.

function greet() {
  console.log(this.animal, "typically sleep between", this.sleepDuration);
}

const obj = {
  animal: "cats",
  sleepDuration: "12 and 16 hours",
};

greet.call(obj); // cats typically sleep between 12 and 16 hours

첫 번째 인자 없이 call()로 함수 호출하기 — 첫 번째 thisArg 매개변수를 생략하면 기본값은 undefined입니다. 비-strict 모드에서는 this 값이 globalThis(전역 객체와 유사)로 치환됩니다.

globalThis.globProp = "foo";

function display() {
  console.log(`globProp value is ${this.globProp}`);
}

display.call(); // Logs "globProp value is foo"

strict mode에서는 this 값이 치환되지 않으므로 undefined로 유지되어 예외를 던집니다.

"use strict";

globalThis.globProp = "foo";

function display() {
  console.log(`globProp value is ${this.globProp}`);
}

display.call(); // throws TypeError: Cannot read the property of 'globProp' of undefined

메서드를 유틸리티 함수로 변환call()this가 함수가 접근된 값이 아니라 일반 매개변수로 전달된다는 점을 제외하면 일반 함수 호출과 거의 동등합니다. 이는 범용 유틸리티 함수의 방식과 유사합니다 — array.map(callback) 대신 map(array, callback)처럼 사용하여, 배열이 아닌 유사 배열 객체에도 map을 쓸 수 있게 합니다.

Array.prototype.slice()를 유사 배열 객체를 실제 배열로 변환하는 데 사용하고 싶다면:

const slice = Array.prototype.slice;

// …

slice.call(arguments);

slice.call을 저장해 일반 함수로 호출할 수는 없습니다. call() 메서드도 역시 자기 this 값을 읽기 때문입니다. 이때는 bind()를 써서 call()this 값을 바인딩할 수 있습니다.

// Same as "slice" in the previous example
const unboundSlice = Array.prototype.slice;
const slice = Function.prototype.call.bind(unboundSlice);

// …

slice(arguments);

더 알아보기