[javascript] 通話と申し込みの違いは何ですか?


Answers

K. Scott Allenはこの問題について素晴らしい書きかけをしています。

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

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

そう:

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

関数を呼び出すためにcallapplyを使用することの違いは何ですか?

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

func.apply();

func.call();

2つの方法のパフォーマンスに違いはありますか? callオーバーをapply最善で、その逆の場合はいつですか?




ここには良いニーモニックがあります。 pplyはA rraysを使用し、 A lwaysは1つまたは2つの引数をとります。 Cを使うときは、引数の数を調べなければなりません。




閉鎖からの抜粋に続く:マイケル・ボリンによる決定的ガイド 。 それは少し長く見えるかもしれませんが、それは多くの洞察力で飽和しています。 「付録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が関数本体で参照されなかった場合、 f(20)obj.addValues(20)の動作は同じになります。

関数はJavaScriptのファーストクラスのオブジェクトであるため、独自のメソッドを持つことができます。 すべての関数は、関数をcall()ときに受信側(つまり、 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() call()も、それが指定されていないときには、それ自身の受信者の値を使って受信者の引数を代用しないので、以下は動作しません:

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

関数の呼び出し時に、 this値をnullまたはundefinedにすることはできません。 call()またはapply()の受信側としてnullまたはundefinedが指定されている場合、代わりにグローバルオブジェクトが受信側の値として使用されます。 したがって、前のコードは、グローバルオブジェクトにvalueという名前のプロパティを追加するのと同じ望ましくない副作用を持っています。

関数が割り当てられている変数を認識していないと考えると便利です。 これは、関数が定義されているときではなく呼び出されたときに、この値がバインドされるという考えを強化するのに役立ちます。

抽出の終わり。







違いは、 call()は関数の引数を別々に取り、 apply()は関数の引数を配列で取りapply()




Call、Apply、Bindの別の例 CallとApplyの違いは明らかですが、 Bindは次のように動作します。

  1. Bindは実行可能な関数のインスタンスを返します
  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
*/



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




メソッドとメソッドの違いは、どのようにパラメータを渡すかです。

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




callapplyが同じことを達成するにもかかわらず、私はあなたがcall使用applyことができないが、 apply使用applyことができる少なくとも一つの場所があると思う。 つまり、継承をサポートしてコンストラクタを呼びたい場合です。

ここで関数を使用すると、他のクラスを拡張してクラスを作成することもできます。

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



Related