FoO의 개발 블로그

[JS 개념정리 2] call, apply, bind 메서드 본문

Programming/FE

[JS 개념정리 2] call, apply, bind 메서드

FoO__511 2024. 6. 30. 21:13

call, apply, bind 메서드는 JavaScript에서 함수의 this 값을 명시적으로 지정하고 함수를 호출하는 방법을 제공한다. Function.prototype의 메서드이므로 모든 (화살표함수를 제외한)함수에서 사용할 수 있다. 

 

call 메서드

  • syntax: func.call(thisArg, arg1, arg2, ...)

주어진 this 값과 개별적으로 제공되는 인수들로 함수를 호출

function greet(greeting) {
    console.log(`${greeting}, ${this.name}`);
}

const person = { name: "Alice" };
greet.call(person, "Hello"); // 출력: Hello, Alice

 

apply 메서드

  • syntax: func.apply(thisArg, [argsArray])

주어진 this 값과 배열(또는 유사 배열 객체)로 제공되는 인수들로 함수를 호출

function introduce(greeting, profession) {
    console.log(`${greeting}, I'm ${this.name} and I'm a ${profession}.`);
}

const person = { name: "Bob" };
introduce.apply(person, ["Hi", "developer"]); // 출력: Hi, I'm Bob and I'm a developer.

 

bind 메서드

  • syntax: func.bind(thisArg[, arg1[, arg2[, ...]]])

새로운 함수를 생성.

생성된 함수의 this는 bind의 첫 번째 인수로 고정되며, 이어지는 인수들은 원본 함수의 인수 앞에 덧붙여진다.

function multiply(a, b) {
    return a * b * this.factor;
}

const doubler = { factor: 2 };
const doubleMult = multiply.bind(doubler);

console.log(doubleMult(3, 4)); // 출력: 24 (3 * 4 * 2)

// 부분 적용(partial application)도 가능합니다
const tripler = { factor: 3 };
const triple6 = multiply.bind(tripler, 6);
console.log(triple6(7)); // 출력: 126 (6 * 7 * 3)

 

함수를 즉시 실행하는 call과 apply와 달리 bind는 새 함수를 반환한다.

bind를 사용하면 부분 적용을 통해 함수의 인수를 미리 설정할 수 있다(partial application).

 

bind 메서드를 이용한 partial application의 예

function multiply(x, y, z) {
    return x * y * z;
}

// x를 2로 고정
const doubleMultiply = multiply.bind(null, 2);
console.log(doubleMultiply(3, 4)); // 출력: 24 (2 * 3 * 4)

// x를 2로, y를 3으로 고정
const sixTimes = multiply.bind(null, 2, 3);
console.log(sixTimes(4)); // 출력: 24 (2 * 3 * 4)

 

const user = {
    name: 'Alice',
    greet: function(greeting, punctuation) {
        console.log(`${greeting}, ${this.name}${punctuation}`);
    }
};

// 'Hello'로 인사말 고정, this를 user 객체로 바인딩
const greetHello = user.greet.bind(user, 'Hello');

greetHello('!'); // 출력: Hello, Alice!
greetHello('.'); // 출력: Hello, Alice.

// 'Hi'와 '!'로 고정
const greetHi = user.greet.bind(user, 'Hi', '!');
greetHi(); // 출력: Hi, Alice!

 

function createElement(type, className, text) {
    const el = document.createElement(type);
    el.className = className;
    el.textContent = text;
    return el;
}

// div 엘리먼트 생성 함수
const createDiv = createElement.bind(null, 'div');

const redDiv = createDiv('red', 'This is a red div');
const blueDiv = createDiv('blue', 'This is a blue div');

// 버튼 생성 함수
const createButton = createElement.bind(null, 'button', 'btn');

const submitButton = createButton('Submit');
const cancelButton = createButton('Cancel');

 

이러한 방식으로 bind를 사용하면 기존 함수를 기반으로 새로운 특화된 함수를 쉽게 만들 수 있다. 코드의 재사용성을 높여 반복을 줄여 더 명확한 코드 작성에 활용이 가능하다.

 

 

사용하는 경우

 

  • 특정 객체의 컨텍스트에서 함수를 실행해야 할 때
  • 콜백 함수의 this 값을 제어해야 할 때
  • 함수 빌려쓰기 패턴(Function barrowing)을 구현할 때
  • 부분 적용을 통해 함수를 커스터마이즈할 때

 

함수 빌려쓰기 패턴(Function borrowing)

Javascript에서 한 객체의 메서드를 다른 객체에서 사용하는 기법이다. 한 객체의 메서드를 다른 객체의 컨텍스트에서 실행해 코드의 재사용성을 높일 수 있다.

 

사용예

배열 메서드 빌려쓰기

const arrayLike = {0: 'a', 1: 'b', 2: 'c', length: 3};
const realArray = Array.prototype.slice.call(arrayLike);
console.log(realArray); // ['a', 'b', 'c']

 

객체 간 메서드 공유

const person = {
  fullName: function(city, country) {
    return `${this.firstName} ${this.lastName}, ${city}, ${country}`;
  }
};

const john = {firstName: "John", lastName: "Doe"};

console.log(person.fullName.call(john, "New York", "USA"));
// John Doe, New York, USA

 

 

유사 배열 객체에 배열 메서드 사용하기(arguments 등)

function sum() {
  return Array.prototype.reduce.call(arguments, (acc, curr) => acc + curr, 0);
}

console.log(sum(1, 2, 3, 4)); // 10

 

  • ES6+ 환경에서는 spread 연산자나 Array.from() 같은 대안이 있어 함수 빌려쓰기를 사용하지 않아도 됨

 

메서드 체이닝

const formatter = {
  format: function(str) {
    return str.toUpperCase();
  }
};

const printer = {
  print: function(str) {
    console.log(str);
  }
};

const formatAndPrint = function(str) {
  const formatted = formatter.format.call(this, str);
  printer.print.call(this, formatted);
};

formatAndPrint("hello"); // HELLO

 

함수 빌려쓰기 패턴은 Javascirpt의 유연성을 활용할 수 있는 방법이다. 하지만 다음과 같이, 더 직관적인 최신 Javascript 기능을 활용할 수 있다면 그를 사용하는 것이 좋다. 

 

// 유사 배열을 배열로 변환
const arrayLike = {0: 'a', 1: 'b', 2: 'c', length: 3};
const realArray = Array.from(arrayLike);

// 배열에서 최대값 찾기
const numbers = [5, 6, 2, 3, 7];
const max = Math.max(...numbers);