logo

DowanKim

46. 함수 바인딩

2026년 4월 15일

자바스크립트

객체 메서드를 콜백으로 전달할 때, 마치 손에 쥔 모래처럼 this가 빠져나가는 경험을 해보셨을 겁니다. 자바스크립트의 함수는 호출되는 방식에 따라 this가 결정되는 '유연함'을 가졌지만, 때로는 이 유연함이 독이 되기도 하죠.


🕵️ 1. 왜 this가 사라질까?

setTimeout 같은 내장 함수에 객체의 메서드를 넘기면, 객체와의 연결고리가 끊어지고 함수 그 자체만 전달됩니다.

  • 현상: setTimeout(user.sayHi, 1000)을 호출하면, 1초 뒤에 user.sayHi가 실행되지만 this는 더 이상 user가 아닌 전역 객체(브라우저에선 window)를 바라보게 됩니다.
  • 결과: this.firstNamewindow.firstName이 되어 undefined를 반환하게 되죠.

🛠️ 2. 해결책 1: 래퍼(Wrapper) 함수

가장 직관적인 방법은 메서드를 직접 호출하는 짧은 함수로 감싸는 것입니다.

setTimeout(() => user.sayHi(), 1000);

  • 원리: 외부 렉시컬 환경에서 user 객체를 가져와서 일반적인 방식으로 호출하므로 this가 유지됩니다.
  • 리스크: 만약 1초가 지나기 전에 user 변수가 다른 객체로 바뀌어버리면, 바뀐 객체의 메서드를 호출하게 되는 취약점이 있습니다.

⚓ 3. 해결책 2: bind 메서드

모든 함수가 가진 내장 메서드 bindthis를 특정 객체로 영구히 고정시킨 특수 객체를 반환합니다.

let sayHi = user.sayHi.bind(user); setTimeout(sayHi, 1000); // 이제 user가 바뀌어도 안전합니다!

  • 특징: bind로 생성된 '묶인 함수(bound function)'는 한 번 고정되면 call이나 apply를 써도 this를 바꿀 수 없습니다.
  • 안정성: 함수가 어디서 어떻게 호출되든 우리가 지정한 context를 끝까지 기억합니다.

🧮 4. 보너스: 부분 적용 (Partial Application)

bindthis 뿐만 아니라 **인수(arguments)**도 미리 고정할 수 있습니다.

function mul(a, b) { return a * b; } // 'this'는 null로 두고, 첫 번째 인수를 2로 고정한 새로운 함수 생성 let double = mul.bind(null, 2); alert( double(3) ); // mul(2, 3) = 6
  • 유용성: 아주 포괄적인 함수를 기반으로 더 구체적인 변형 함수(예: double, triple)를 만들 때 가독성을 획기적으로 높여줍니다.

🎙️ 기술 면접 대비 (Interview Questions)

Q1. bind를 두 번 연속해서 사용하면(f.bind(obj1).bind(obj2)) this는 어떻게 되나요? (중급)

답변: 첫 번째 바인딩인 **obj1**이 유지됩니다. bind가 반환하는 객체는 생성 시점의 컨텍스트만 기억하며, 이미 바인딩된 함수를 다시 bind하더라도 내부의 this를 변경할 수 없도록 설계되어 있습니다.

Q2. 화살표 함수에서 bind를 사용할 수 있나요? (심화)

답변: 문법적으로 호출은 가능하지만 this를 바인딩하는 효과는 없습니다. 화살표 함수는 자신만의 this를 가지지 않고 외부 스코프의 this를 결정적으로 사용하기 때문입니다. 따라서 화살표 함수에 bind를 쓰는 것은 의미가 없으며, 주로 일반 함수 표현식에서 사용됩니다.


💡 Tech Lead의 한 줄 인사이트

"리액트의 클래스형 컴포넌트 시절에는 생성자에서 메서드들을 일일이 bind(this) 해주는 게 일상이었죠. 지금은 화살표 함수를 클래스 필드로 써서 이 문제를 우아하게 넘기곤 합니다. 하지만 라이브러리 개발이나 로우레벨 로직을 짤 때 bind를 활용한 부분 적용 기법은 여전히 코드의 재사용성을 높여주는 강력한 무기입니다."