2025-01-24
내일배움캠프 Node.js 트랙 60일차
자바스크립트의 함수 바인딩
자바스크립트에서 함수는 객체로 취급되며, 따라서 변수에 저장되거나 다른 객체의 속성으로 할당될 수 있다. 그러나 함수가 일반 변수처럼 동작할 수 있다는 점에서, 호출 시 컨텍스트(context)가 변경될 수 있다는 점은 주의가 필요하다. 이때, 원하는 컨텍스트로 함수를 호출할 수 있도록 도와주는 개념이 "바인딩(binding)"이다.
자바스크립트의 함수 바인딩은 평소엔 존재감이 없는 듯하다가 잊을만하면 발목을 붙잡는 개념이다. 특히 객체 메서드를 콜백으로 전달할 때 발생하는 'this' 정보 손실 문제를 해결하는 데 핵심적인 역할을 한다.
'this' 컨텍스트 손실 문제
객체 메서드가 객체 외부에서 호출될 때 'this' 컨텍스트가 손실되는 문제가 발생한다. this
는 함수 호출 방식에 따라 값이 결정된다. 객체의 메서드로 호출된 함수는 해당 객체를 this
로 참조하지만, 독립적으로 호출된 함수는 this
가 undefined
가 되거나 전역 객체를 참조한다. 예를 들어 setTimeout 사용할 땐 콜백 함수가 필요한데, 이 인자로 객체 메서드를 전달하려 했을 때 이런 현상이 일어난다.
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(user.sayHi, 1000);
// 실행 결과 : Hello, undefined!
해결 방법
래퍼 함수 사용
가장 간단한 해결책은 래퍼 함수를 사용하는 것이다. 이 방법은 외부 렉시컬 환경에서 객체를 가져와 메서드를 호출한다.
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(function() {
user.sayHi(); // Hello, John!
}, 1000);
bind 메서드 사용
함수의 bind
메서드는 새로운 함수를 생성하면서, this
의 값을 고정시키는 역할을 한다. 이를 통해 함수 호출 방식에 상관없이 지정된 this
값을 유지할 수 있다.
기본 사용법
let user = {
firstName: "John",
sayHi() {
console.log(`Hello, ${this.firstName}!`);
}
};
let sayHi = user.sayHi.bind(user);
sayHi(); // "Hello, John!"
위 예제에서 user.sayHi
메서드는 bind
를 사용하여 user
객체를 this
로 고정했다. 이제 sayHi
를 호출할 때마다 this
는 항상 user
를 가리킨다
인자 바인딩
bind
는 this
뿐만 아니라 함수의 인수도 고정할 수 있다. 이를 "부분 적용(partial application)"이라고 한다.
function multiply(a, b) {
return a * b;
}
let double = multiply.bind(null, 2);
console.log(double(3)); // 6
console.log(double(5)); // 10
multiply.bind(null, 2)
는 multiply
함수의 첫 번째 인수를 2로 고정한 새로운 함수를 반환한다.
바인딩이 필요한 상황
콜백에서의 컨텍스트 문제
콜백 함수에서 this
가 예상치 못한 값을 참조하는 경우가 자주 발생한다. 이를 해결하기 위해 바인딩이 필요하다.
let user = {
firstName: "Alice",
sayHi() {
console.log(`Hi, ${this.firstName}!`);
}
};
setTimeout(user.sayHi.bind(user), 1000); // "Hi, Alice!"
만약 bind
를 사용하지 않는다면 setTimeout
에 전달된 함수는 this
가 전역 객체나 undefined
를 참조하게 된다.
메서드 전달
객체의 메서드를 다른 변수에 할당하거나, 인자로 전달할 때도 bind
를 사용하여 this
를 고정해야 한다.
let user = {
firstName: "Bob",
sayHi() {
console.log(`Hi, ${this.firstName}!`);
}
};
let sayHi = user.sayHi;
sayHi(); // 에러 또는 예상치 못한 동작
let boundSayHi = user.sayHi.bind(user);
boundSayHi(); // "Hi, Bob!"
출처 : 함수 바인딩