call
とapply
を使って関数を呼び出すことの違いは何ですか?
var func = function() {
alert('hello!');
};
func.apply();
vs func.call();
前述の2つの方法にはパフォーマンスの違いがありますか? call
よりapply
を使用するのが最善の場合、またその逆の場合はいつですか。
違いは、apply
を使用すると、arguments
を配列として使用して関数を呼び出すことができるという点です。 call
では、パラメーターを明示的にリストする必要があります。 " a rrayの場合は" _ a _ 、 c omの場合は _ c _ になります。
apply および 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が Niceの記事を書いています .
基本的に、それらは関数の引数の扱い方が異なります。
Apply()メソッドが2番目のパラメータとして配列を必要とすることを除いて、apply()メソッドはcall()と同じです。配列はターゲットメソッドの引数を表します。 "
そう:
// 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
が速くなります。
これは良いニーモニックです。 A用途 A配列と Alwaysは1つか2つの引数を取ります。使うとき Cあなたがしなければならないすべて C引数の数を数えます。
これは古いトピックですが、.callは.applyよりもわずかに速いということを指摘しておきます。その理由はわかりません。
JsPerf、 http://jsperf.com/test-call-vs-apply/3 を参照してください。
[UPDATE!
]
Douglas Crockfordはこの2つの違いについて簡単に述べています。これはパフォーマンスの違いを説明するのに役立つかもしれません... http://youtu.be/ya4UHuXNygM?t=15m52s
Applyは引数の配列を取りますが、Callは0個以上の個々のパラメータを取ります。ああっ!
.apply(this, [...])
.call(this, param1, param2, param3, param4...)
からの抜粋に従ってください:Michael Bolinによる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がWebブラウザで実行されるときのグローバルオブジェクトです。これは驚くべき振る舞いにつながります。
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.addValues
とf
は同じ関数を参照していますが、呼び出しのたびに受信側の値が異なるため、呼び出し時の動作は異なります。このため、this
を参照する関数を呼び出すときは、呼び出されるときにthis
が正しい値を持つようにすることが重要です。 this
が関数本体で参照されていなければ、f(20)
とobj.addValues(20)
の動作は同じになります。
関数はJavaScriptのファーストクラスオブジェクトなので、独自のメソッドを持つことができます。すべての関数はメソッドを呼び出すときにレシーバ(つまりthis
が参照するオブジェクト)を再定義することを可能にするメソッドcall()
とapply()
を持っています。メソッドシグネチャは次のとおりです。
/**
* @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()
の受信者として指定されている場合は、代わりにグローバルオブジェクトがreceiverの値として使用されます。したがって、前のコードは、value
という名前のプロパティをグローバルオブジェクトに追加するという同じ望ましくない副作用があります。
関数を、それが割り当てられている変数についての知識を持っていないと考えることは役に立つかもしれません。これは、関数の定義時ではなく関数の呼び出し時にthisの値が制限されるという考えを補強するのに役立ちます。
抽出の終わり.
あるオブジェクトが別のオブジェクトの関数を借用することは時々役に立ちます。つまり、借用するオブジェクトは貸された関数をそれ自身のものであるかのように単に実行するということです。
小さなコード例:
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
これらのメソッドはオブジェクトに一時的な機能性を与えるのにとても便利です。
呼び出し、適用、バインドの別の例CallとApplyの違いは明らかですが、 Bind は次のように機能します。
}
function Person(name) {
this.name = name;
}
Person.prototype.getName = function(a,b) {
return this.name + " " + a + " " + b;
}
var reader = new Person('John Smith');
reader.getName = function() {
// Apply and Call executes the function and returns value
// Also notice the different ways of extracting 'getName' prototype
var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
console.log("Apply: " + baseName);
var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy");
console.log("Call: " + baseName);
// Bind returns function which can be invoked
var baseName = Person.prototype.getName.bind(this, "is a", "boy");
console.log("Bind: " + baseName());
}
reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/
'valueForThis'引数を使用した例を示します。
Array.prototype.Push = function(element) {
/*
Native code*, that uses 'this'
this.put(element);
*/
}
var array = [];
array.Push(1);
array.Push.apply(array,[2,3]);
Array.prototype.Push.apply(array,[4,5]);
array.Push.call(array,6,7);
Array.prototype.Push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9]
**詳細: http://es5.github.io/#x15.4.4.7 *
Call()は、カンマ区切りの引数を取ります。例:
.call(scope, arg1, arg2, arg3)
そしてapply()は引数の配列を取ります。
.apply(scope, [arg1, arg2, arg3])
ここにいくつかのより多くの使用例があります: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/
MDNドキュメントのFunction.prototype.apply() から:
Apply()メソッドは、指定された
this
値と、配列(または配列に似たオブジェクト)として与えられた引数を使って関数を呼び出します。構文
fun.apply(thisArg, [argsArray])
MDNのドキュメントのFunction.prototype.call() から:
Call()メソッドは、指定された
this
値と引数を個別に指定して関数を呼び出します。構文
fun.call(thisArg[, arg1[, arg2[, ...]]])
JavaScriptの Function.applyおよびFunction.callから :
Apply()メソッドが2番目のパラメータとして配列を必要とすることを除いて、apply()メソッドはcall()と同じです。配列は、ターゲットメソッドの引数を表します。
var doSomething = function() {
var arr = [];
for(i in arguments) {
if(typeof this[arguments[i]] !== 'undefined') {
arr.Push(this[arguments[i]]);
}
}
return arr;
}
var output = function(position, obj) {
document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>';
}
output(1, doSomething(
'one',
'two',
'two',
'one'
));
output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [
'one',
'two',
'two',
'one'
]));
output(3, doSomething.call({one : 'Steven', two : 'Jane'},
'one',
'two',
'two',
'one'
));
this Fiddle も参照してください。
基本的な違いは、call()
は 引数リスト を受け入れ、apply()
は 単一の引数配列 を受け入れることです。
これはちょっとした投稿です、私はこれについて書いた:
http://sizeableidea.com/call-versus-apply-javascript/ /
var obj1 = { which : "obj1" },
obj2 = { which : "obj2" };
function execute(arg1, arg2){
console.log(this.which, arg1, arg2);
}
//using call
execute.call(obj1, "dan", "stanhope");
//output: obj1 dan stanhope
//using apply
execute.apply(obj2, ["dan", "stanhope"]);
//output: obj2 dan stanhope
//using old school
execute("dan", "stanhope");
//output: undefined "dan" "stanhope"
違いは、call()
は関数の引数を別々に受け取り、apply()
は配列内の関数の引数を受け取ることです。
以下のように呼び出しを区別してメソッドを適用することができます。
CALL:引数付きの関数は個別に提供します。渡す引数がわかっている場合、または渡す引数がない場合は、callを使用できます。
APPLY:引数を配列として指定して関数を呼び出します。関数に渡す引数の数がわからない場合は、applyを使用できます。
Apply over callを使用する利点があります。引数の数を変更する必要はありません。渡された配列を変更できます。
性能に大きな違いはありません。しかし、配列はapplyメソッドで評価する必要があるので、呼び出しはapplyよりも少し速いと言えます。
両方の呼び出しと適用は、関数が実行されるときにthis
値を強制するために使用されます。唯一の違いは、call
がn+1
引数を取ることです。ここで、1はthis
と'n' arguments
です。 apply
は2つの引数のみを取ります。1つはthis
、もう1つは引数配列です。
apply
に比べてcall
に見られる利点は、多くの労力なしで他の関数に関数呼び出しを簡単に委譲できることです。
function sayHello() {
console.log(this, arguments);
}
function hello() {
sayHello.apply(this, arguments);
}
var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');
hello
を使用してsayHello
をapply
に簡単に委譲したことを確認しますが、call
ではこれを達成するのは非常に困難です。
これらのメソッドとの違いは、パラメータの渡し方です。
「Aは配列、Cはコンマ」は便利なニーモニックです。
call
とapply
は同じことを達成していますが、call
を使用できないがapply
しか使用できない場所が少なくとも1つあると思います。それはあなたが継承をサポートしたいとき、そしてコンストラクタを呼びたいときです。
これは、他のクラスを拡張することによってクラスの作成をサポートするクラスを作成するための機能です。
function makeClass( properties ) {
var ctor = properties['constructor'] || function(){}
var Super = properties['extends'];
var Class = function () {
// Here 'call' cannot work, only 'apply' can!!!
if(Super)
Super.apply(this,arguments);
ctor.apply(this,arguments);
}
if(Super){
Class.prototype = Object.create( Super.prototype );
Class.prototype.constructor = Class;
}
Object.keys(properties).forEach( function(prop) {
if(prop!=='constructor' && prop!=='extends')
Class.prototype[prop] = properties[prop];
});
return Class;
}
//Usage
var Car = makeClass({
constructor: function(name){
this.name=name;
},
yourName: function() {
return this.name;
}
});
//We have a Car class now
var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat
var SuperCar = makeClass({
constructor: function(ignore,power){
this.power=power;
},
extends:Car,
yourPower: function() {
return this.power;
}
});
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6
主な違いは、呼び出しを使用して、スコープを変更して通常どおり引数を渡すことができますが、applyを使用すると、引数を配列として使用して呼び出すことができます(配列として渡します)。しかし、それらがあなたのコードで何をするべきかという点では、それらはかなり似ています。
この関数の構文はapply()の構文とほぼ同じですが、基本的な違いは、call()は引数リストを受け入れ、apply()は引数の単一配列を受け入れます。
お分かりのように、大きな違いはありませんが、それでも、call()またはapply()を使用したい場合があります。たとえば、次のコードを見てください。これは、applyメソッドを使用して、MDNから配列内の最小数と最大数を見つけます。
// 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)
したがって、主な違いは、引数を渡す方法だけです。
電話:
function.call(thisArg, arg1, arg2, ...);
適用:
function.apply(thisArg, [argsArray]);
call()
とapply()
はどちらもFunction.prototype
にあるメソッドです。したがって、それらはプロトタイプチェーンを介してすべての関数オブジェクトで利用できます。 call()
とapply()
の両方とも、指定されたthis
の値で関数を実行できます。
call()
とapply()
の主な違いは、引数を渡す方法です。 call()
とapply()
の両方で、最初の引数として、値にしたいオブジェクトをthis
として渡します。他の引数は次のように異なります。
call()
を使えば、普通に引数を入力しなければなりません(2番目の引数から始めて)apply()
では、引数の配列を渡す必要があります。let obj = {
val1: 5,
val2: 10
}
const summation = function (val3, val4) {
return this.val1 + this.val2 + val3 + val4;
}
console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array
console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually
this
の値は、JavaScriptの中では扱いにくい場合があります。 this
の値は 関数が定義されているときではなく、関数が実行されたときに決定されます。 もし私たちの関数が正しいthis
バインディングに依存しているなら、この振る舞いを強制するためにcall()
とapply()
を使うことができます。例えば:
var name = 'unwantedGlobalName';
const obj = {
name: 'Willem',
sayName () { console.log(this.name);}
}
let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable
copiedMethod();
// this is now window, unwantedGlobalName gets logged
copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged