hyunmin!
개발자 정현민
hyunmin!
  • All (18)
    • Web (7)
      • JavaScript (3)
      • TypeScript (1)
      • React (3)
    • Life (11)
      • 부스트캠프 (11)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
hELLO · Designed By 정상우.
hyunmin!

개발자 정현민

자바스크립트의 bind, call, apply
Web/JavaScript

자바스크립트의 bind, call, apply

2021. 9. 11. 15:39

자바스크립트의 함수는 함수처럼, 객체처럼, 객체 지향의 생성자처럼 동작하며, 함수에 붙어있는 프로토타입 객체를 통해 공통되는 메소드를 공유한다. 즉, 함수에서 사용할 수 있는 메소드가 있다. 이번 포스팅은 그중 bind, call, apply에 관한 정리이다.

👆 this

class Five {
  constructor() {
    this.number = 5;
  }

  printNumber() {
    console.log(this.number);
  }
}

위와 같이 클래스가 정의되어있다.

아래 코드의 실행 결과는 눈에 훤히 보인다.

const five = new Five();
five.printNumber(); // 5

그렇다면 다음과 같은 상황일 때도 같은 결과인지 한번 생각해보자.

const five = new Five();
const printFive = five.printNumber;
printFive(); // Cannot read property 'number' of undefined

함수를 변수에 전달하고 호출했을 뿐인데 실행결과가 다르다. 이는 printFive 변수에 printNumber 함수가 객체에서 분리되어 전달되었기 때문이다.

객체에서 분리되었기 때문에 printFive 함수 실행에서 this는 undefined이다. number 변수가 있을 리가 없다.

좀 더 범용적인 예시를 들겠다.

const five = new Five();
setTimeout(five.printNumber, 0); // undefined

Node.js 환경에서 printNumber 함수 내의 this는 Timeout 객체이다. 마찬가지로 number 변수를 기대하기 힘들다.

함수를 전달할 때, this(컨텍스트)를 사라지지 않게 하려면 어떤 방법이 있을까.

🪢 bind

모든 함수는 this를 수정하게 해주는 내장 메서드 bind를 제공한다. 기본 문법은 다음과 같다.

const boundFunc = func.bind(context);

이름에서 내포하듯 bind 함수는 묶어준다. 무엇과 무엇을 묶냐면 func 함수에서의 this와 bind의 파라미터인 context를 묶는다. 즉, boundFunc 함수에서의 this는 context가 된다. 이전의 예시로 다시 살펴보겠다.

const five = new Five();
const printFive = five.printNumber.bind(five);
printFive() // 5

printNumber내의 this를 five로 고정됐기 때문에 printFive 함수를 호출하면 five 객체 값인 5가 출력된다. 물론 setTimeout에도 bind 된 함수를 전달할 수 있다.

const five = new Five();
const printFive = five.printNumber.bind(five);
setTimeout(printFive, 1000); // 5

five.printNumber = function() {
  console.log(4);
}

객체의 함수가 변경되어도 변경 이전의 함수를 실행하는 것을 볼 수 있다.

function printNumber(name) {
  console.log(name, this.number);
}

printNumber('hyunmin'); // hyunmin undefined

const printFive = printNumber.bind({number: 5});
printFive('hyunmin') // hyunmin 5

printNumber 함수에 {number: 5} 객체를 바인딩했고, 바인딩된 함수 printFive 함수를 호출할 때 파라미터로 hyunmin을 넘기면 hyunmin 5를 출력한다.

☎️ call, apply

function printNumber() {
  console.log(this.number);
}

printNumber.bind({number: 5})(); // (1)
printNumber.call({number: 5});   // (2)
printNumber.apply({number: 5});  // (3)

(1), (2), (3) 실행 결과가 모두 같다.

call과 apply는 함수를 즉시 실행다는 것에 bind와 차이가 있다. 함수가 나중에 사용되어야 한다면 bind 그 외에는 call과 apply를 쓸 수 있다. call 과 apply의 근본적인 차이점은 call은 함수 함수에 전달될 인수 리스트를 받는 데 비해, apply는 인수들의 단일 배열을 받는다는 점이다. 이게 무슨 말인지는 다음 예제를 보면 알 수 있다.

function printNumber(first, second, third) {
  console.log(this.number, first, second, third);
}

printNumber.call({number: 5}, 1, 2, 3);
printNumber.apply({number: 5}, [1, 2, 3]);

'이 정도로 친절하다고?'라는 생각이 든다. 상황에 따라서 유용하게 나눠 쓸 수 있겠다.

ℹ️ tip

두 번 bind 하면?

function printNumber() {
  console.log(this.number);
}

const printFive = printNumber.bind({number: 5}).bind({number: 444});
printFive() // 5

한번 묶인 함수는 처음 묶였을 그 당시의 컨텍스트만 기억한다. 즉, 한번 bind 하면 다시 bind 할 수 없다. bind의 바람기 없는 면모를 확인할 수 있는 부분이다.

bind 함수의 프로퍼티?

function printNumber() {
  console.log(this.number);
}
printNumber.user = 'hyunmin';
console.log(printNumber.user); // hyunmin

const printFive = printNumber.bind({number: 5});
console.log(printFive.user); // undefined

bind를 적용하면 또 다른 객체가 반환된다. 새로운 객체엔 user 프로퍼티가 없으므로 undefined가 출력된다.

📚 참조

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

https://ko.javascript.info/bind

'Web > JavaScript' 카테고리의 다른 글

자바스크립트의 Data Binding  (0) 2021.10.07
자바스크립트의 Promise 직접 구현하기  (13) 2021.09.20
    'Web/JavaScript' 카테고리의 다른 글
    • 자바스크립트의 Data Binding
    • 자바스크립트의 Promise 직접 구현하기
    hyunmin!
    hyunmin!

    티스토리툴바