MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Function.prototype.apply()

현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.

Summary

apply() 메소드는 주어진 this값과 arguments로 함수를 호출합니다.
arguments에는 배열( 또는 유사배열객체 array-like object)가 올 수 있습니다.

Note: 이 함수의 구문은 거의 call()구문과 유사합니다., 기본적으로 다른 점은  call()은 함수에 전달될 여러 개의 인자를 받는데 비해, apply()는 배열로 된 하나의 인자를 받는다는 점입니다.

Syntax

fun.apply(thisArg, [argsArray])

Parameters

thisArg
호출될 함수에게 지정될 this의 값입니다. 호출된 함수 내에서 this가 전달된 thisArg인자와 다를 수 있으므로 주의: 만약 함수가 non-strict mode 모드에서 실행 중이라면, nullundefined 는 전역객체로 대체되고, 기본값은 레퍼객체로 대체됩니다.
argsArray
유사배열객체, 특히 함수가 호출될 때 생성된 arguments객체, 함수에 전달할 인자가 없는 경우는 null 또는 undefined. ECMAScript 5에서는 배열 대신 유사배열객체로 일괄처리 됩니다. 하단에 있는browser compatibility 참조.

Description

이미 존재하는 함수를 호출할 때 다른 this객체를 할당할 수 있습니다. this는 현재 객체로 호출한 객체를 참조합니다. apply를 이용하면 새로운 객체마다 메소드를 재작성할 필요없이 한 번만 작성해 다른 객체에 상속시킬 수 있습니다.

apply는 지원되는 인자의 타입만 제외하면 call()과 매우 유사합니다. 명명된 인자조합 대신 인자배열을 사용할 수 있습니다. apply에서는 배열리터럴이나 Array객체를 사용할 수 있는데, 예를들어 배열리터럴은 fun.apply(this, ['eat', 'bananas'])과 같은 형태로, 배열객체는 fun.apply(this, new Array('eat', 'bananas'))와 같이 사용됩니다.

argsArray인자에는 arguments도 사용할 수 있습니다. arguments는 함수의 지역변수입니다. 호출된 함수에 명시적으로 선언되지 않은 모든 인자를 위해 사용할 수 있습니다. 따라서 apply를 사용할 때 호출된 객체의 인자를 알 필요가 없습니다. arguments를 이용해 호출된 객체의 모든 인자를 전달할 수 있으며, 호출된 객체는 그 인자를 조작할 수 있게 됩니다.

ECMAScript 5판에서는 유사배열객체를 사용할 수 있으며, 구체적으로는 length속성을 갖고 0 이상 length미만 범위의 정수를 속성으로 갖는 모든 종류의 객체의 사용을 인정하고 있습니다. 예를 들면 NodeList 또는 { 'length': 2, '0': 'eat', '1': 'bananas' }과 같은 고유하게 정의된 객체를 사용할 수 있습니다.

주의: Chrome14와 Internet Explorer 9를 포함한 대부분의 브라우저느 아직 유사배열객체를 apply에 사용할 수 없으며 오류가 출력됩니다.

Examples

예: apply를 이용한 생성자 체인

apply를 이용하면 java처럼 객체에 대해 constructors 를 연결할 수 있습니다. 다음 예제에서 Function 에 construct라는 메서드를 생성하여, 인자의 목록 대신 유사배열객체를 construct와 함께 사용할 수 있게 합니다.

Function.prototype.construct = function (aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

Note: 위에서 사용된 Object.create()는 비교적 새로운 것입니다. 클로저를 사용한 대체 메소드는 다음과 같습니다.

Function.prototype.construct = function(aArgs) {
  var fConstructor = this, fNewConstr = function() { fConstructor.apply(this, aArgs); };
  fNewConstr.prototype = fConstructor.prototype;
  return new fNewConstr();
};

Example usage:

function MyConstructor() {
  for (var nProp = 0; nProp < arguments.length; nProp++) {
    this['property' + nProp] = arguments[nProp];
  }
}

var myArray = [4, 'Hello world!', false];
var myInstance = MyConstructor.construct(myArray);

alert(myInstance.property1);                // alerts 'Hello world!'
alert(myInstance instanceof MyConstructor); // alerts 'true'
alert(myInstance.constructor);              // alerts 'MyConstructor'

Note: 위에 등장한 네이티브가 아닌 Function.construct메소드는 몇몇 네이티브 생성자에는 작동하지 않습니다(예를 들어 Date) 이런 경우 Function.prototype.bind 메소드를 이용해야 합니다(예를들어 Date 생성자에 사용할 [2012, 11, 4] 와 같은 배열을 가정한다면, new (Function.prototype.bind.apply(Date, [null].concat([2012, 11, 4])))() 같이 생각해볼 수 있습니다- 어쨌든 이것은 최선의 선택이라고는 할 수 없으며, 어떤 제품수준의 환경에서도 사용해서는 안 될 것입니다.

예: 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); /* This about equal to Math.max(numbers[0], ...)
                                            or 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, 3만 apply에 전달되어 온 것처럼 작동합니다). 만약 사용하는 배열 변수의 수가 수만을 초과하는 경우에는 복합적인 전략을 강구해야할 것입니다:한 번에 전달할 배열을 분할하여 apply하기:

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]);

예: "monkey-patching"에 apply사용

apply는 FireFox의 내장 함수나 JS 라이브러리에 monkey-patch를 위한 가장 좋은 방법입니다. 주어진 someobject.foo 함수를 다음과 같은 방법으로 변형합니다:

var originalfoo = someobject.foo;
someobject.foo = function() {
  // 함수가 호출되기 전에 할 일
  console.log(arguments);
  // 보통 때처럼 함수를 호출함:
  originalfoo.apply(this, arguments);
  // 함수가 호출된 후 할 일
}

이 메소드는 특히 다양한 .on([event]...Devtools Inspector에서 사용할 수 있는 event)과 같은 API가 없는 객체의 이벤트나 인터페이스를 디버깅할 때 유용합니다.

Specifications

Specification Status Comment
ECMAScript 3rd Edition. Standard Initial definition. Implemented in JavaScript 1.3.
ECMAScript 5.1 (ECMA-262)
The definition of 'Function.prototype.apply' in that specification.
Standard  
ECMAScript 6 (ECMA-262)
The definition of 'Function.prototype.apply' in that specification.
Release Candidate  

Browser compatibility

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (Yes) (Yes) (Yes) (Yes) (Yes)
ES 5.1 generic array-like object as arguments ? 4.0 (2.0) ? ? ?
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support (Yes) (Yes) (Yes) (Yes) (Yes) (Yes)
ES 5.1 generic array-like object as arguments ? ? 4.0 (2.0) ? ? ?

See also

문서 태그 및 공헌자

 이 페이지의 공헌자: bsidesoft
 최종 변경: bsidesoft,