자바스크립트의 함수는 함수처럼, 객체처럼, 객체 지향의 생성자처럼 동작하며, 함수에 붙어있는 프로토타입 객체를 통해 공통되는 메소드를 공유한다. 즉, 함수에서 사용할 수 있는 메소드가 있다. 이번 포스팅은 그중 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
'Web > JavaScript' 카테고리의 다른 글
자바스크립트의 Data Binding (0) | 2021.10.07 |
---|---|
자바스크립트의 Promise 직접 구현하기 (13) | 2021.09.20 |