[javascript] 통화와 적용의 차이점은 무엇입니까?

함수 사용 callapply호출 의 차이점은 무엇입니까 ?

var func = function() {
  alert('hello!');
};

func.apply(); vs func.call();

위에서 언급 한 두 가지 방법간에 성능 차이가 있습니까? 언제 call이상 을 사용 하는 것이 가장 apply좋습니까?



답변

차이점은 배열로 apply함수를 호출 할 수 있다는 것입니다 arguments. call매개 변수를 명시 적으로 나열해야합니다. 유용한 니모닉은 ” 에 대한 rray와 C 에 대한 C OMMA.”

apply and call 에 대한 MDN 설명서를 참조하십시오 .

의사 구문 :

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

또한 ES6부터 함수 spread와 함께 사용할 수 있는 배열 가능성이 있습니다 . 여기서call 호환성을 확인할 수 있습니다 .

샘플 코드 :

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator


답변

K. Scott Allen 은이 문제에 대해 좋은 글남겼 습니다.

기본적으로 함수 인수를 처리하는 방법이 다릅니다.

apply () 메서드는 call ()과 동일하지만 apply ()에는 두 번째 매개 변수로 배열이 필요합니다. 배열은 대상 메소드의 인수를 나타냅니다. “

그래서:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);


답변

각 함수의 사용시기에 대한 부분에 대답하려면 apply전달할 인수의 수를 모르거나 인수가 이미 배열 또는 배열과 같은 오브젝트 ( arguments자신의 인수를 전달 하는 오브젝트)에있는 경우 사용하십시오. call인수를 배열로 랩핑 할 필요가 없으므로 그렇지 않으면 사용하십시오 .

f.call(thisObject, a, b, c); // Fixed number of arguments

f.apply(thisObject, arguments); // Forward this function's arguments

var args = [];
while (...) {
    args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments

예를 들어 인수를 전달하지 않으면 함수를 호출 하기 call때문에 선호 합니다. 존재하지 않는 인수에 함수를 적용 하고 있음을 의미합니다 .apply

apply인수를 사용하여 배열에서 래핑하는 경우 (예 : f.apply(thisObject, [a, b, c])대신 f.call(thisObject, a, b, c))를 제외하고는 성능 차이가 없어야합니다 . 나는 그것을 테스트하지 않았으므로 차이점이있을 수 있지만 브라우저마다 매우 다를 수 있습니다. 그것은 가능성이 높습니다 call이미 배열의 인수를하지 않는 경우입니다 빠른 apply입니다 빨리 당신이 할 경우.


답변

좋은 니모닉이 있습니다. pply는 사용 rrays 및 법이지는 하나 개 또는 두 개의 인수를 사용합니다. 당신이 사용하는 경우 C를 당신이 가지고있는 모든 C는 인수의 수를 ount.


답변

이것은 오래된 주제이지만 .call이 .apply보다 약간 빠르다는 것을 지적하고 싶었습니다. 왜 그런지 정확히 말할 수 없습니다.

jsPerf, http://jsperf.com/test-call-vs-apply/3 참조


[ UPDATE!]

Douglas Crockford는 성능 차이를 설명하는 데 도움이되는 두 가지 차이점을 간략하게 언급합니다 … http://youtu.be/ya4UHuXNygM?t=15m52s

Apply는 인수의 배열을 취하지 만 Call은 0 개 이상의 개별 매개 변수를 사용합니다! 아하!

.apply(this, [...])

.call(this, param1, param2, param3, param4...)


답변

Michael Bolin의 Closure : The Definitive Guide 에서 발췌 한 내용 입니다. 약간 길어 보일 수 있지만 통찰력이 풍부합니다. “부록 B. 자주 JavaScript 개념을 오해”:


어떤 this함수가 호출되는 경우를 말합니다

형식의 함수를 호출 할 때 foo.bar.baz()객체를 foo.bar수신자라고합니다. 함수가 호출되면 다음 값으로 사용되는 수신자입니다 this.

var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
  for (var i = 0; i < arguments.length; i++) {
    this.value += arguments[i];
  }
  return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);

함수가 호출 될 때 명시적인 수신자가 없으면 전역 오브젝트가 수신자가됩니다. 47 페이지의 “goog.global”에서 설명한대로 window는 웹 브라우저에서 JavaScript가 실행될 때 전역 객체입니다. 이것은 놀라운 행동으로 이어진다 :

var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN

비록 obj.addValuesf동일한 기능을 참조하십시오, 그들은 수신기의 값이 각 통화에서 다르기 때문에 전화했을 때 다르게 동작합니다. 따라서을 참조하는 함수를 호출 할 때 호출 될 때 올바른 값 this을 갖도록하는 것이 중요합니다 this. 명확하게 말하면 this함수 본문에서 참조되지 않은 경우 동작 f(20)obj.addValues(20)동일합니다.

함수는 JavaScript에서 일류 객체이므로 자체 메서드를 가질 수 있습니다. 모든 함수에는 메소드가 call()있으며 함수를 호출 할 때 apply()수신자 (즉, 참조하는 오브젝트)를 재정의 할 수 this있습니다. 메소드 서명은 다음과 같습니다.

/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;

참고 유일한 차이 call()apply()그 인 call()반면, 각각의 인자로서의 기능 파라미터를 수신하는 apply()단일 어레이로 수신 :

// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);

로 다음의 호출은, 동등 f하고 obj.addValues동일한 기능을 참조하십시오

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

그러나 수신자 인수가 지정되지 않은 경우 수신자 인수를 대체하기 위해 자체 수신자의 값을 사용 call()하거나 apply()사용 하지 않기 때문에 다음이 작동하지 않습니다.

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

의 값은 this절대 null또는 undefined함수가 호출 될 수 없습니다 . 경우 null또는 undefined받는 수신기로 공급된다 call()또는 apply()전역 객체 대신에 수신기에 대한 값으로서 사용된다. 따라서 앞의 코드는 value전역 개체에 이름이 지정된 속성을 추가 할 때와 동일한 바람직하지 않은 부작용이 있습니다.

함수가 할당 된 변수에 대한 지식이없는 것으로 생각하면 도움이 될 수 있습니다. 이는 함수가 정의 될 때가 아니라 함수가 호출 될 때이 값이 바인드 될 것이라는 아이디어를 강화하는 데 도움이됩니다.


추출물의 끝.


답변

때로는 한 객체가 다른 객체의 기능을 빌리는 것이 유용합니다. 즉, 빌린 객체는 빌려 진 함수를 마치 마치 마치 마치 마치 마치 마치 마치 자신의 함수처럼 실행합니다.

작은 코드 예 :

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

};

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true);

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

이 메소드는 객체에 임시 기능을 제공하는 데 매우 유용합니다.