
자바스크립트 완벽 가이드를 읽고 정리한 글입니다.
call()과 apply() & bind()메서드
call()과 apply()는 함수를 마치 다른 객체의 메서드인 것처럼 간접적으로 호출한다. call()과 apply()의 첫 번째 인자는 함수를 호출할 객체이다. 이 인자가 호출 컨텍스트이며 함수 바디 안에서 this 키워드의 값이다.
함수 f()를 인자 없이 객체 o의 메서드로 호출할 때는 call()과 apply()중 어느것을 사용해도 된다.
f.call(o);
f.apply(o);
화살표 함수는 자신이 정의된 컨텍스트의 this 값을 상속한다. 이 값은 call()과 apply() 메서드로 덮어 쓸 수 없다. 화살표 함수에서 call()과 apply()를 호출하면 첫 번째 인자는 무시되는 것이나 마찬가지다.
call()을 사용할 때 첫 번째 인자인 호출 컨텍스트 다음에 오는 인자는 호출될 함수에 전달된다. 이 인자는 화살표 함수에서도 무시되지 않는다.
예를들어 함수 f()에 숫자 두 개를 전달하면서 f()가 객체 o의 메서드인 것처럼 호출하려면 다음과 같다.
f.call(o,1,2);
apply() 메서드도 비슷하지만, 함수에 전달할 인자가 배열로 제공된다.
f.apply(o, [1,2]);
함수가 받는 인자 개수에 제한이 없다면 apply() 메서드를 사용해서 임의의 길이를 가진 배열을 전달해 함수를 호출할 수 있다. ES6 이후라면 분해 연산자를 사용해도 되지만, ES5 코드에서는 apply()를 사용한 경우도 있다.
예를들어 분해 연산자 없이 숫자 배열에서 가장 큰 숫자를 찾을 때 apply()메서드로 배열 요소를 Math.max() 함수에 전달할 수 있다.
let biggest = Math.max.apply(Math, arrayOfNumbers);
bind() 메서드
bind()의 주 목적은 함수를 객체에 결합(bind)하는 것이다. 함수 f에서 bind() 메서드를 호출하면서 객체 o를 전달하면 새 함수를 반환한다. 새 함수를 함수로 호출하면 원래 함수 f가 o의 메서드로 호출된다. 새 함수에 전달한 인자는 모두 원래 함수에 전달된다.
function f(y) {return this.x + y;} // 결합할 함수.
let o = {x:1}; // 결합될 객체
let g = f.bind(o); // g(x)를 호출하면 o에서 f()를 호출한다.
g(2); // 3
let p = {x:10, g}; // g()를 이 객체의 메서드로 호출한다.
p.g(2) // 3: g는 여전히 o에 결합되어 있다.
화살표 함수는 자신이 정의된 환경의 this 값을 상속하며 이 값은 bind()에서 덮어 쓸 수 없으므로, 위 코드의 함수 f()를 화살표 함수로 정의했다면 결합이 제대로 이루어지지 않을 것이다. bind()를 호출하는 목적은 대개 화살표 함수가 아닌 함수를 화살표 함수처럼 사용하는 것이므로 화살표 함수에서 결합이 이루어지지 않는 다는 것은 문제가 되지 않는다. bind() 메서드는 단순히 함수를 객체에 결합하는 것으로 끝나지 않는다. bind()에 전달하는 인자 중 첫번째를 제외한 나머지는 this 값과 함께 결합된다. 이러한 부분 적용은 화살표 함수에도 동작한다. 부분 적용은 함수형 프로그래밍에서 널리 쓰이는 기법이며 커링(currying)이라고 부르기도 한다.
let sum = (x,y) => x + y; // 인자의 합을 반환한다.
let succ = sum.bind(null, 1); // 첫 번째 인자와 1을 결합한다.
succ(2) // 3: x는 1이고 y 인자로 2를 전달했다.
function f(y,z) {return this.x + y + z;}
let g = f.bind({x: 1}, 2); // this와 y를 결합한다.
g(3) // 6: this.x는 1, y는 2에 결합됐으며 z는 3이다.
bind()가 반환하는 함수의 name 프로퍼티는 bind()를 호출한 함수의 name 앞에 “bound”를 붙인 값이다.