web-dev-qa-db-ja.com

電話と申請の違いは何ですか?

callapplyを使って関数を呼び出すことの違いは何ですか?

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

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

前述の2つの方法にはパフォーマンスの違いがありますか? callよりapplyを使用するのが最善の場合、またその逆の場合はいつですか。

2901
John Duff

違いは、applyを使用すると、argumentsを配列として使用して関数を呼び出すことができるという点です。 callでは、パラメーターを明示的にリストする必要があります。 " a rrayの場合は" _ a _ c omの場合は _ c _ になります。

apply および call に関するMDNのドキュメントを参照してください。

疑似構文

theFunction.apply(valueForThis, arrayOfArgs)

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

ES6では、 spreadcall関数で使用するための配列への可能性もあります、互換性を見ることができます ここ

サンプルコード

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
3466
flatline

K. Scott Allenが Niceの記事を書いています .

基本的に、それらは関数の引数の扱い方が異なります。

Apply()メソッドが2番目のパラメータとして配列を必要とすることを除いて、apply()メソッドはcall()と同じです。配列はターゲットメソッドの引数を表します。 "

そう:

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

各関数をいつ使用するかについての部分に答えるには、渡す引数の数がわからない場合、またはそれらが既に配列または配列に似たオブジェクト(自分自身を転送するための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が速くなります。

152
Matthew Crumley

これは良いニーモニックです。 A用途 A配列と Alwaysは1つか2つの引数を取ります。使うとき Cあなたがしなければならないすべて C引数の数を数えます。

105
Joe

これは古いトピックですが、.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...)

91
kmatheny

からの抜粋に従ってください: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.addValuesfは同じ関数を参照していますが、呼び出しのたびに受信側の値が異なるため、呼び出し時の動作は異なります。このため、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]);

fobj.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またはundefinedcall()またはapply()の受信者として指定されている場合は、代わりにグローバルオブジェクトがreceiverの値として使用されます。したがって、前のコードは、valueという名前のプロパティをグローバルオブジェクトに追加するという同じ望ましくない副作用があります。

関数を、それが割り当てられている変数についての知識を持っていないと考えることは役に立つかもしれません。これは、関数の定義時ではなく関数の呼び出し時にthisの値が制限されるという考えを補強するのに役立ちます。


抽出の終わり.

75

あるオブジェクトが別のオブジェクトの関数を借用することは時々役に立ちます。つまり、借用するオブジェクトは貸された関数をそれ自身のものであるかのように単に実行するということです。

小さなコード例:

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

これらのメソッドはオブジェクトに一時的な機能性を与えるのにとても便利です。

33
tjacks3

呼び出し、適用、バインドの別の例CallとApplyの違いは明らかですが、 Bind は次のように機能します。

  1. バインドは実行可能な関数のインスタンスを返します
  2. 最初のパラメータは ' this 'です
  3. 2番目のパラメータは、 カンマ区切りの 引数リストです( Call のように)

}

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
*/
25
Mahesh

'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 *

23
user669677

Call()は、カンマ区切りの引数を取ります。例:

.call(scope, arg1, arg2, arg3)

そしてapply()は引数の配列を取ります。

.apply(scope, [arg1, arg2, arg3])

ここにいくつかのより多くの使用例があります: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

20
Mark Karwowski

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 も参照してください。

18
John Slegers

基本的な違いは、call() 引数リスト を受け入れ、apply() 単一の引数配列 を受け入れることです。

11
Rakesh Kumar

これはちょっとした投稿です、私はこれについて書いた:

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"
10
Dan

違いは、call()は関数の引数を別々に受け取り、apply()は配列内の関数の引数を受け取ることです。

7
Sanjib Debnath

以下のように呼び出しを区別してメソッドを適用することができます。

CALL:引数付きの関数は個別に提供します。渡す引数がわかっている場合、または渡す引数がない場合は、callを使用できます。

APPLY:引数を配列として指定して関数を呼び出します。関数に渡す引数の数がわからない場合は、applyを使用できます。

Apply over callを使用する利点があります。引数の数を変更する必要はありません。渡された配列を変更できます。

性能に大きな違いはありません。しかし、配列はapplyメソッドで評価する必要があるので、呼び出しはapplyよりも少し速いと言えます。

6
Praveen D

両方の呼び出しと適用は、関数が実行されるときにthis値を強制するために使用されます。唯一の違いは、calln+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を使用してsayHelloapplyに簡単に委譲したことを確認しますが、callではこれを達成するのは非常に困難です。

5
Raghavendra

これらのメソッドとの違いは、パラメータの渡し方です。

「Aは配列、Cはコンマ」は便利なニーモニックです。

5
venkat7668

callapplyは同じことを達成していますが、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
4

主な違いは、呼び出しを使用して、スコープを変更して通常どおり引数を渡すことができますが、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]);
3
Alireza

概要:

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
2