2011-12-28 12 views
60

皆さんは、callapplyの方法をJavascriptで使用するために、どのようなコンテキストを説明することができますか?コールを使用してJavascriptで適用するコンテキスト?

なぜ関数を直接呼び出す代わりにcallapplyを使用するのですか?

+2

[この読み取り](https://t.co/BVQPwfqqnO) () 'あなたの質問の中核と思われる。 Javascriptの関数呼び出しプリミティブを理解する必要があります。 –

答えて

20

callまたはapplyを使用する場合は、機能内のthisコンテキストを変更することができます。

JavaScriptでは、実行コンテキストではなく、thisが現在のオブジェクトを参照するのではなく、呼び出し元によって設定されます。

あなたはnewキーワードthisが正しく(コンストラクタ関数内の)新しいオブジェクトを参照します使用して関数を呼び出す場合...

しかし、他のすべてのケースで - によって明示的に設定しない限り、thisはグローバルオブジェクトを参照します

+0

'obj.whatever();'構文を使用している場合は、呼び出し元のobjを参照することがあります。 –

+0

"ただし、他のすべての場合 - これは明示的に呼び出しによって設定されない限りグローバルオブジェクトを参照します"は次のように修正する必要があります: "しかし、他のすべてのケースでは、呼び出しによって明示的に設定されない限り、 Ecmascript 3またはEcmascript 5(またはそれ以降)を非厳密モードで使用していますが、厳密モードのEcmascript 5(またはそれ以降)では明示的に設定されていないとこれは未定義となり、JSエンジンはこれにアクセスすると例外をスローします。提供されているコードスニペットについての質問のみ、なぜおもちゃと食べ物が提供されているのですか?を参照してください:http://stackoverflow.com/questions/9822561/why-is-this-in-an-anonymous-function-undefined-when-using-strict –

68

thisの値を関数に渡す場合は、callまたはapplyを使用します。つまり、ある特定のオブジェクトのメソッドであるかのように関数を実行したいということです。 2つの唯一の違いは、callはパラメータがコンマで区切られているとしますが、applyは配列内のパラメータを必要とすることです。

コンストラクタが連鎖さMozilla's apply page、から例:何Product.apply(this, arguments)

function Product(name, price) { 
    this.name = name; 
    this.price = price; 

    if (price < 0) 
     throw RangeError('Cannot create product "' + name + '" with a negative price'); 
    return this; 
} 

function Food(name, price) { 
    Product.apply(this, arguments); 
    this.category = 'food'; 
} 
Food.prototype = new Product(); 

function Toy(name, price) { 
    Product.apply(this, arguments); 
    this.category = 'toy'; 
} 
Toy.prototype = new Product(); 

var cheese = new Food('feta', 5); 
var fun = new Toy('robot', 40); 

は以下の通りである:ProductコンストラクタがFoodToyコンストラクタの各々内の関数として印加され、これらのオブジェクトの各々インスタンスがthisとして渡されています。したがって、それぞれFoodおよびToyは、this.nameおよびthis.categoryプロパティを持つようになりました。

+5

プロトタイプはProductオブジェクトに置き換えられますか? – davids

+0

@davids質問にバンプするだけの理由:なぜToy.prototype = new Product(); 'を実行する必要があるのですか?私はこれをテストし、それらの行を削除すると最終結果に違いはないようです。 – adrianp

+6

@ davids&@adrianp:食品と玩具を製品から継承する必要があります。次の例を見てください:http://jsfiddle.net/Shawn/xNEYf/ 'Toy.prototype = new Product();'を削除しましたが、 'Food.prototype = new Product();'を残しました。製品ですが、おもちゃはありません。私はまた、Productのプロトタイプにメソッドを追加し、継承の欠如をより明白にするためにメソッドを追加しました(コンソールを開いてコードを実行し、FoodはProductから継承したメソッドを呼び出すことができますが、Toyはエラーをスローすることはできません) 。 – Shawn

3

jQueryの経験がある場合は、ほとんどの関数がthisオブジェクトを使用していることがわかります。たとえば、collection.each(function() { ... }); この関数の内部では、"this"はイテレータオブジェクトを参照します。これは1つの可能な使用法です。

私は個人的にリクエストのキューを実装するために.apply()を使用しました - 私は、引数の配列をキューにプッシュし、実行のために時間が来たら、要素をとり、それをハンドラ関数の引数として渡します.apply()を使用します。したがって、最初の引数として引数の配列を渡す必要がある場合は、コードをきれいにします。それは別の例です。

一般に、関数を呼び出す方法が存在することを覚えておいてください。プログラムを実装するためにいつでも便利に使用できることがあります。

6

異なるthisの値で機能を実行させたい場合は、.call()を使用します。指定したとおりにthisの値を設定し、指定されたとおりに引数を設定してから関数を呼び出します。 .call()との違いは、関数が実行されたときにポインタthisの値になります。関数を正常に実行すると、javacriptはthisポインタ(通常はグローバルコンテキストwindow)をオブジェクトのメソッドとして呼び出さない限りそれを決定します。 .call()を使用する場合は、thisの設定を正確に指定します。

.apply()は、関数に渡す引数が配列の場合に使用します。 .apply()は、特定のthis値で関数を実行させることもできます。 .apply()は、他のソースからの引数が不確定な場合に最もよく使用されます。現在の関数に渡された引数の配列を含む特別なローカル変数argumentsを使用して、ある関数呼び出しから別の関数呼び出しに引数を渡すことがよくあります。

.call().apply()のMDNリファレンスページが役立っています。

+0

ありがとう、あなたはとてもうまく説明します。最後に、最初の引数の使い方を理解してください。 –

0

thisArgを別のものに設定することは、applyを使用する目的であるとは思いません。

適用の目的は、それらの値を引数として必要とする関数に値の配列を渡すことです。

これは普及したオペレータによる通常の日常的な使用に取って代わられています。

// Finding the largest number in an array 
`Math.max.apply(null, arr)` becomes `Math.max(...arr)` 

// Inserting the values of one array at the start of another 
Array.prototype.unshift.apply(arr1, arr2); 
// which becomes 
arr1 = [...arr2, ...arr1] 
0

あなたはObject Oriented Programmingの経験を持っている場合は、電話して適用されますが、あなたが相続とそれを比較すれば意味をなさないし、プロパティまたは子クラスから親クラスのメソッド/関数をオーバーライドします。これは、次のようにJavaScriptでのコールと似ています)(適用 `を呼び出すと` `呼び出したときに私は` thisArg`のポイントを理解する助け

function foo() { 
    this.helloworld = "hello from foo" 
} 
foo.prototype.print = function() { 
    console.log(this.helloworld) 
} 

foo.prototype.main = function() { 
    this.print() 
} 


function bar() { 
    this.helloworld = 'hello from bar' 
} 
// declaring print function to override the previous print 
bar.prototype.print = function() { 
    console.log(this.helloworld) 
} 

var iamfoo = new foo() 

iamfoo.main() // prints: hello from foo 

iamfoo.main.call(new bar()) // override print and prints: hello from bar 
関連する問題