2012-03-06 10 views
9

私はまだJavaScriptのクロージャの概念と混同しています。母関数が返った後で母関数内で作成された変数にアクセスする内部関数の能力がクロージャであるという点がわかります。 しかし、私はまだなぜ関数内に変数を作成することができれば、ローカル変数を保護するために内部関数を作成する必要があるのですか?Javascript Closures

+7

Closureのための美しいチュートリアルhttps://developer.mozilla.org/ja/JavaScript/Guide/Closures – Pranav

+0

これは最高の記事であると私は考えています:http://javascript-reference.info/ javascript-closures-for-dummies.htm – Sang

答えて

1

スコープ付き変数を使用して内部関数を作成する必要がある理由は、オブジェクト指向のカプセル化です。基本的に私的な変数です。

変数は「閉じています」。

// constructor function 
var myObject = function(message) { 
    // private - scope is function level. It's CLOSED OVER the the inner function (closure). 
    //   not delcared as a JSON property so not visible externally 
    var value = 0; 
    // constructor returns JSON object with public methods 
    // always constructed from the myObject var so it always hands back the same instance 
    // of the public methods 
    return { 
     // nested functions have access to outer function variables. 
     increment: function (inc) { 
      value ++; 
     }, 
     getValue: function() { 
      return value; 
     }, 
     // the inner function even has access to the outer function's args! 
     getMessage: message 
    } 
}; 

return文を見てください。パブリックインターフェイスを返します。プライベート変数が内部関数にあるため、プライベート変数にアクセスできるメソッドがあります。 JavaScriptsの関数スコープ変数を使用して、オブジェクト指向のカプセル化を作成しています。

その後、私はそれが好きなことができます。

var obj = myObject('Hello World'); 
obj.increment(); 
obj.increment(); 
console.log(obj.getValue()); 
console.log(obj.getMessage); 
// should be undefined 
console.log(obj.value); 

注意をこの時点で、消費者は、保護/カプセル化された値またはメッセージにアクセスすることはできません。

ここではキッカーです。オブジェクトは変更可能であるため、呼び出し元はメソッドを追加したり、メソッドを置き換えたりすることができます。だから、誰かが内部を公開するメソッドを追加できると思うだろう。しかし、彼らは機能の範囲のためにできません(閉鎖 - 彼らは閉鎖されています)。ネストされた関数だけが外部関数の変数にアクセスできます。したがって、呼び出し元が内部メソッドを返すメソッドを追加した場合、呼び出し元はアクセスを取得できず、未定義になります。

出力上記のコード:サイドノートとして

2 
Hello World 
undefined 

、私はnode.js

でJavaScriptを実行しているここでクロージャを使用してモジュールのパターンに優れたブログ記事です:

http://www.yuiblog.com/blog/2007/06/12/module-pattern/

0

ポイントは変数が共有されていることです2つの機能。内部関数で変数を宣言した場合、外部関数は変数にアクセスできないため、共有されません。

+0

したがって、内部関数の変数がマザー関数変数から参照されても、内部関数の変数は最後に変更されたときの値になりますか? – DevX

+0

はい、いいえ。内部関数の変数を外部関数から参照することはできないので、内部変数はその値を保持しています。 Sinethaの例を 'alert(inner。つまり、私が内部関数を繰り返し呼び出すときでさえ、母関数によって作成された変数から参照されている内部変数は、それが変更されたときに見られることになります(つまり、foo) '(=> undefined) – Teemu

1

あなたの質問にちょうど答えました。内側の関数は変数を保護しています。 jsFiddle

(function outer(){ 
    var foo = 'bar'; 
    function inner(){ 
     var foo = 'OMG NO!'; 
    } 
    alert(foo);//alerts 'bar' 
})() 
1

FROM MDN CLOSURES

why to use: 

閉鎖は、あなたがそのデータを操作する関数をいくつかのデータ(環境)を関連付けることができます。これは、オブジェクト指向プログラミングと明らかに類似しています。オブジェクト指向プログラミングでは、オブジェクトによって、あるデータ(オブジェクトのプロパティ)を1つ以上のメソッドに関連付けることができます。

when not to use 

マイナス両方の処理速度とメモリ消費の面でスクリプトのパフォーマンスに影響するよう閉鎖が特定のタスクのために必要されていない場合は、不必要に他の関数内の関数を作成することは賢明ではありません。

たとえば、新しいオブジェクト/クラスを作成する場合、通常、メソッドはオブジェクトコンストラクタに定義するのではなく、オブジェクトのプロトタイプに関連付ける必要があります。その理由は、コンストラクタが呼び出されるたびにメソッドが再割り当てされる(つまり、すべてのオブジェクトが作成される)ためです。

0

内部関数の変数を宣言した場合、内部関数を呼び出すたびに新しい変数が作成されます。以前の呼び出しによって行われた変更は失われます。

しかし、変数が外部関数で宣言されている場合、内部関数への複数の呼び出しは同じ変数を参照し、1つの呼び出しは両方とも同じバージョンのスコープになっている限り、前の呼び出しの変更を参照します。外側の機能。

+0

以前に呼ばれた時?私の頭にあるのはそれだから、内部関数の変数は、内部関数を呼び出すと、変数の値を母関数から引き継ぐことになります。 – DevX

3

外部関数の変数が外部関数が返った後に存在するように、内部関数を作成する必要があります。

簡単機能検討:プログラムの制御は「F()」関数の開始から流れるとき、変数「x」は唯一の「アクティブ」(生き存在しない)であることを

function f() { 
    var x = 0; 
    return ++x; // x=1 
} // Once the function has exited then "x" no longer exists. 

注それの終わりまでしかし、我々は内部機能に「X」を囲むならば、xがいる限り、内部の機能が行うように生きる:私たちは、「グラム()」を呼び出すとき

function g() { 
    var x = 0; 
    return function() { 
    // Now "x" will live for as long as this function. 
    return ++x; 
    } 
}; 
var counter = g(); 
counter(); // => 1 
counter(); // => 2 
counter(); // => 3 

は、今、私たちは別の関数を取得し、「x」がアクティブでありますその関数が変数によって参照されている限りです。

2

なぜクロージャを使用しますか?

(function(){ 
    var current_page = 1; 
    function previous_page() { 
     current_page--; 
     // update interface 
    } 
    function next_page() { 
     current_page++; 
     // update interface 
    } 
    // a bit of jQuery, ok? 
    $('#previous').click(previous_page); 
    $('#next').click(next_page); 
})(); 

ルック:私たちは、「#previous」と「#next」ボタンのクリックイベントのために行動を添付した、...何のグローバル変数、グローバル空間で定義されていなくてもすべての機能を持っていない、まだページング機能閉鎖せずにどうしますか?どのように関数内でcurrent_page変数を定義するのですか?

+0

'PageUpdater'オブジェクトをコーディングして、ページを追跡し、GUIを更新することができます。これはもっと読みやすくなります。もちろん、プライベートにするためのアクセス修飾子がないので、インスタンス変数は他の人にも見えるでしょう。 (これはJSのもう一つの弱点であり、複雑なコードを促進します。 –

0

クロージャについて正しい答えがたくさんありますが、多くの人が尋ねる多くの人がより高いレベルの簡単な説明を最初に探している間は、常に実際に技術的になるようです。

私は車のように思っています。あなたが車を運転するとき、多くの複雑なプロセスが進行していますが、普通の人は平均日にこれらについて知る必要はありません。これらの複雑さは、ペダル、ブレーク、シフター、ステアリングホイールなどを使いやすくするクロージャーによって隠された「プライベート」変数と考えることができます。

クロージャの目的は何ですか?スクリプトをもっと使いやすくするために、すべての複雑な変数などを隠すため。スクリプト内のすべての変数を心配する必要がある場合は、スクリプト内の関数を使用するたびに、すぐに非常に難しくなります。 YAY CLOSURES!

関連する問題