Skip to main content Link Menu Expand (external link) Document Search Copy Copied

call, apply, bind

참고 블로그 함수를 호출하는 방법에는 함수명 뒤에 ()를 붙여 호출하는 방법과 call, apply를 사용하여 호출하는 방법이 있습니다.

그 방법을 알아보도록 하겠습니다.

Function.prototype.call()

func.call(thisArg[, arg1[, arg2[, ...]]])

  • thisArg: func호출에 제공되는 this의 값
  • arg1, arg2, … : func가 호출할 인수들
let person1 = {
    name: 'Jo'
};

let person2 = {
    name: 'Kim',
    study: function() {
        console.log(this.name + '이/가 공부를 하고 있습니다.');
    }
};

person2.study(); // Kim이/가 공부를 하고 있습니다.

// call()
person2.study.call(person1); // Jo이/가 공부를 하고 있습니다.

예시를 보면 person2의 study메소드에서 this는 person2를 가리키고 있습니다. 그 이유는 this게시물을 보시면 알 수 있습니다. 하지만 call을 통해 this를 person1으로 넣어주고 있기 때문에 person1을 가리키게 됩니다.

Function.prototype.apply()

func.apply(thisArg, [argsArray])

  • thisArg: func호출에 제공되는 this의 값
  • arg1, arg2, … : func가 호출할 인수를 지정하는 유사 배열 객체
  • 반환값: 지정한 this 값과 인수들로 호출한 함수의 결과

첫 번째 매개변수는 call과 동일합니다. 하지만 두 번째 매개변수를 배열 혹은 유사 배열 객체로 넣는다는 차이점이 있습니다.

apply 와 내장함수 사용

apply 를 보다 효과적으로 이용하면 일부 내장 함수는 어떤 작업에 대해서는 배열과 루프없이 쉽게 처리됩니다. 다음 예제에서는 배열에서 최대값과 최소값을 구하기 위해 Math.max/Math.min 함수를 이용하고 있습니다.

// min/max number in an array
var numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
var max = Math.max.apply(null, numbers);
// 이는 Math.max(numbers[0], ...) 또는 Math.max(5, 6, ...)
// 와 거의 같음

var min = Math.min.apply(null, numbers);

// vs. simple loop based algorithm
max = -Infinity, min = +Infinity;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max) {
    max = numbers[i];
  }
  if (numbers[i] < min) {
    min = numbers[i];
  }
}

하지만 이러한 방식으로 apply 를 사용하는 경우 주의해야 합니다. JavaScript 엔진의 인수 길이 제한을 초과하는 위험성에 대해 이해할 필요가 있습니다. 함수에 너무 많은(대략 몇 만개 이상) 인수를 줄 때의 상황은 엔진마다 다른데(예를 들어 JavaScriptCore의 경우 인수의 개수 제한은 65536), 상한이 특별히 정해져 있지 않기 때문입니다. 어떤 엔진은 예외를 던집니다. 더 심한 경우는 실제 함수에 인수를 전달했음에도 불구하고 참조할 수 있는 인수의 수를 제한하고 있는 경우도 있습니다(이러한 엔진에 대해 더 자세히 설명하면, 그 엔진이 arguments의 상한을 4개로 했다고 하면[실제 상한은 물론 더 위일 것입니다], 위 예제 코드의 전체 배열이 아니라 5, 6, 2, 3apply 에 전달되어 온 것처럼 작동합니다).

만약 사용하는 배열 변수의 수가 수만을 초과하는 경우에는 복합적인 전략을 강구해야할 것입니다:한 번에 전달할 배열을 분할하여 사용하기:

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null,
                                arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);

Function.prototype.bind()

func.bind(thisArg[, arg1[, arg2[, ...]]])

  • thisArg: 바인딩 함수가 타겟 함수의 this에 전달하는 값
  • arg1, arg2, … : func가 호출할 인수들

bind()는 새롭게 바인딩한 함수를 만듭니다. 바인딩한 함수는 원본 함수 객체를 감싸는 함수입니다. bind()call(), apply()와 같이 함수가 가리키고 있는 this를 바꾸지만 호출되지는 않습니다.따라서 변수를 할당하여 호출하는 형태로 사용합니다.

let person1 = {
    name: 'Jo'
};

let person2 = {
    name: 'Kim',
    study: function() {
        console.log(this.name + '이/가 공부를 하고 있습니다.');
    }
};

person2.study(); // Kim이/가 공부를 하고 있습니다.

// bind()
let student = person2.study.bind(person1);

student(); // Jo이/가 공부를 하고 있습니다.

arguments 조작

위 메소드들을 쓰는 예로, 함수의 arguments를 조작할 때 사용합니다. arguments는 함수라면 처음부터 갖고 있는 숨겨진 속성인데 바로 함수에 들어온 인자를 배열 형식으로(배열X, 유사 배열) 반환합니다.

function example() {
  console.log(arguments.join());
}
example(1, 'string', true); // Uncaught TypeError: arguments.join is not a function

형태는 배열이지만, 배열이 아니라 유사 배열이기 때문에, 배열의 메소드는 쓸 수 없습니다. 이 때 call이나 apply를 사용할 수 있습니다.

function example3() {
  console.log(Array.prototype.join.call(arguments));
}
example3(1, 'string', true); // '1,string,true'

배열의 프로토타입에 있는 join 함수를 빌려 쓰는 것입니다. this는 arguments를 가리키게 합니다. join외에도 다른 메소드를 이 방식으로 사용할 수 있습니다.