2011-12-13 11 views
11

JavaScriptのクロージャでMozillaの開発者サイトを見ていて、このコード例がありました。javascriptで関数を返す、スコープとクロージャを理解する

function makeAdder(x){ 
    return function (y) { 
     console.log(y + " this is y") 
     console.log(x + " this is x") 
     return x + y; 
     } 
} 
var add10 = makeAdder(10); 
console.log(add10(2)); // 12 

ここで、X属性が設定されていることを理解していますが、yの範囲がどのように影響を受けるかは分かりません。私はそのリターン関数を知っていますが、私の脳はそれを参照していないときにyをどのように設定できるかを視覚化しようと努力しました。誰かが説明できますか?

答えて

13

makeAdderは、yパラメータを渡すことができる関数を返します。起動時に設定され、xが新しい関数の作成時に設定されます(呼び出し時はmakeAdder)。この例の場合には、出力が書かれたことに相当します

function add10(y) { 
    return 10 + y; 
} 

console.log(add10(2)); // 12 

新しいものは何もここで起こっていません。サンプルコードでは、主にクロージャがxのために作成されていることを示しています。

のでmakeAdderは、ここでは、適切な名前です:あなたはそれに10を渡すとき、それはあなたがその新しい機能へを渡すすべてに10を追加します機能を与えます。

var add10 = makeAdder(10); 
var add20 = makeAdder(20); 

console.log(add10(1) + add20(1)); // 32 

確かに、追加するために、2つのパラメータを受け入れて追加する機能があれば簡単です。しかし、これは追加の教訓ではありません、それは閉鎖の教訓です。上記のコードで

var buttons = document.getElementsByClassName('myButton'); 
for(var i = 0; i < buttons.length; i++) { 
    buttons[i].onclick = function() { 
     alert('You clicked button ' + i); 
    }; 
} 

、いずれかのボタンがクリックされる前にiセット全体を通じて反復しているでしょう:

現実の世界のシナリオは次のようなものかもしれません。したがって、すべてボタンは、buttons.lengthのいずれかを警告します。代わりに、あなたは次のようんでした:

var makeAlert = function(x) { 
    return function() { 
     alert('You clicked button ' + x); 
    }; 
}; 

for(var i = 0; i < buttons.length; i++) { 
    buttons[i].onclick = makeAlert(i); 
} 

をここでの違いは、(全体の繰り返しの後になる)ボタンがクリックされたときにiが使用されていないということですが、それは反復中を使用しています、 iに と表示されているときは、各ボタンに異なる値が設定されています。

変数makeAlertを作成する代わりに、この種のコードが匿名関数として記述され、すぐに呼び出されることがよくあります。だからadd10 = makeAdder(10);が実際にこの機能を返して

for(var i = 0; i < buttons.length; i++) { 
    buttons[i].onclick = (function(x) { 
     return function() { 
      alert('You clicked button ' + x); 
     }; 
    })(i); 
} 
+0

私は、私の脳はまだイムはちょうどしようと、それを取得しようとしている見ます私の頭の中のadd10(3)があなたの設定Xがなぜそうではないと言っているかのように、yが渡されたり参照されていないときに設定されている方法を見てください。 ( – mustafa

+1

いいえ、 'makeAdder(10)'の 'x'は' 10'に設定されています。 'add10(2)'の 'y'は' 2'に設定されています。 –

+0

しかし、 makeAdder(10、2)は同じことをしているのですか?それとも本質的にmakeAdder(10)ですか?(2)? あまりにもありがとうございました:) – mustafa

1

関数makeAdderは、呼び出されると関数を返します。 makeAdderが返すこの関数は、1つのパラメータを受け入れます。これはyと呼ばれます。

変数yは、makeAdderによって返された関数の呼び出し中にのみ存在します。 isが呼び出されるたびに作成され、関数が復帰すると破棄されます。

一方、変数xは、makeAdderが呼び出されたときに作成され、関数makeAdderが作成したクロージャによって保持されます。返される関数への参照がなくなったときに破棄されます。

1

:そして

function(y) { 
    console.log(y + " this is y") 
    console.log("10" + " this is x") 
    return 10 + y; 
} 

add10(2)はどこでも2でYを置換する、その関数を呼び出している:

console.log("2" + " this is y") 
    console.log("10" + " this is x") 
    return 10 + 2; 
以下のコードは、上記のコードと本質的に同等です
+0

しかし、あなたはあなたの目標を知っていますか、あなたが正しいパラメータにアクセスしていたかを知ろうとしているのを見て、ちょうど初心者のように聞こえて申し訳ありません、私は私の問題が戻ってくる関数はvars等とは対照的です。 – mustafa

+0

まず、xを10に置き換え、その関数をadd10に代入すると思います。初めてmakeAddedを呼び出すときは、最初の関数をターゲットにしていて、2回目の関数をターゲットにしています(最初にネストされましたが、今度はvarに割り当てられ、その後beeingが呼び出されます)。 Firebugでconsole.log(add10)を実行すると、割り当て後に自分自身を見ることができます。 – alessioalex

+0

それで、makeAdder(10)の書き込みのようなビットです(2)? あまりにも多くの人に感謝:) – mustafa

2

関数は、実行可能コードとプロパティを含む特別なオブジェクトと見ることができます。すべての関数には、定義されたときの環境を表す特別な[scope]プロパティがあります。ある関数が別の関数から返された場合、古い環境へのこの参照は "closure"内の新しい関数によって閉じられます。

あなたがvar add10 = makeAdder(10)を呼び出すときに何が起こるかは、返される関数のxはそれのスコープにバインドされている値10、およびコールconsole.log(add10(2))プリント12を持っていることです。

クロージャーを視覚化するためにthisの記事を読むことを検討してください。閉鎖のより詳細な説明は、hereで見つけることができます。

+0

リンクメイトに感謝 – mustafa

5

何を求めていることは、あなたのために何かをする機能である:

function giveMeAFunctionThatBeeps(){ 
    return function() { 
     alert('Beep!'); 
     } 
} 

var beeper = giveMeAFunctionThatBeeps(); 

beeper(); // beeps! 

実際giveMeAFunctionThatbeepsは、あなたが欲しいものを行う関数を与えるだけの工場です。彼らが提供している

は例では、ブザーと同じことをやっているが、あなたはまた、値を渡している:、

function giveMeAFunctionThatBeepsANumber(x){ 
    return function() { 
     alert('Beep ' + x); 
     } 
} 

これはブザーを返します(それは覚えている工場です)が、ブザーはxの値を警告します。

ただし、この値は、あなたが最初にビープ音を作成するときに設定されている:

var beeper = giveMeAFunctionThatBeeps(5); 

beeper(); // beeps 5! 

ブザーが今値5をビープ音立ち往生されており、我々はそれについて何もすることはできません。

あなたが任意の数のビープ音を発するブザー作成する場合、次の例は次のとおりです。今、私たちは私たちがに番号を差し込むことができる機能を提供するために工場を求めていると

function giveMeAFunctionThatBeepsANumber(){ 
    return function (x) { 
     alert('Beep ' + x); 
     } 
} 

var beeper = giveMeAFunctionThatBeeps(); 

beeper(6); // beeps 6! 
beeper(7); // beeps 7! 

を。

はその後最後に、元の例では、上記の両方を組み合わせている:我々はブザーを作成するとき、我々は、上記のように覚えておいてください2に渡してい

function giveMeAFunctionThatBeepsANumber(x){ 
    return function (y) { 
     alert('Beep ' + (x + y)); 
     } 
} 

var beeper = giveMeAFunctionThatBeeps(2); 

、私たちはその後、これを変更することはできません!それは常にビープ音2 ...

...しかし、それは、パラメータをとる関数を返す(値2で事前に設定)の工場ですので、我々はそれを実行したとき、我々はそれをカスタマイズすることができます。

beeper(6); // beeps 8! because x was set when we created it, and y is what we pass in. 
+0

これはあなたの時間のためにとてもありがとうございます – mustafa

+0

私はクロージャーに問題があったと私はちょうど読んでトンと同じことのための異なる説明トンを発見した:) – NibblyPig

関連する問題