2017-02-25 6 views
0

このクロージャの動作によって混乱します。私は閉鎖に関するいくつかのSOの記事(this oneを含む)とMDNの文書を読んだが、この動作の説明は見ていない。クロージャの変数を返すと参照の代わりにコピーが作成されています

下のコードサンプルでは、​​変数cacheと、それを変更する関数preloadと、その値を記録する関数reportを含むクロージャを作成しています。また、渡されたオブジェクトにそれらへの参照を添付する。

'use strict'; 

var o = {}; 

(function(obj) { 
    var cache = {'initialized': false}; 

    function preload(assets, done) { 
     console.log('Preloading. Value of cache is', cache); 
     cache = {}; 

     for (var i = 0; i < assets.length; i++) { 
      cache[assets[i]] = assets[i]; 
     } 
    } 

    function report() { 
     console.log('Cache from inside is ', cache); 
    } 

    function get_cache() { 
     return cache; 
    } 

    obj.cache = cache; 
    obj.preload = preload; 
    obj.report = report; 
})(o); 

// {initialized: false}, as expected 
o.report(); 

// {initialized: false}, as expected 
console.log('Cache from outside is ', o.cache); 

// I expect this to change cache to {1:1, 2:2, 3:3} 
o.preload([1, 2, 3]); 

// {1:1, 2:2, 3:3}, as expected 
o.report(); 

// {initialized: false}, NOT as expected. Why? 
console.log('Cache from outside is ', o.cache); 

私の期待を閉鎖が提供objからcacheを添付するとき、それはクロージャ内の変数への参照を代入していることを私の理解に基づいています。しかし、私が見ているふるまいは、obj.cacheが閉鎖のcacheコピーを得ていることを示唆しています。

cacheのコピーはいつ作成されますか?その理由は何ですか?あなたが最初にobj.cache = cache;を呼び出すと

+0

なぜ 'get_cache'ではなく、' cache'変数の初期値を公開していますか? – Bergi

+1

あなたはコピーを作成しているので、 'cache = {}'。クロージャーだけが変数 'cache'そのものであることに注意してください。変数 'obj.cache'はクロージャではなく、CやJavaや他の言語のような通常の参照/ポインタ代入です。そのため、 'obj.cache'は' cache'によって指されるのと同じオブジェクトを指すが、変数 'cache'は指さない。つまり、 'obj.cache = cache'はキャッシュへのポインタを値で割り当てます(ほとんどのプログラミング言語のようにポインタのコピーを作成します) – slebetman

答えて

2

、あなたはcacheが(このオブジェクト:{'initialized': false})を指していることを同じオブジェクトをobj.cacheポイントを作っている

あなたがpreloadを呼び出すときにその後、あなたは別の変数cacheを指します、新しいオブジェクト:cache = {};cache変数は新しいオブジェクトを指していますが、obj.cacheはまだ最初に作成された古いオブジェクトを指しています。

これは、クロージャ内のcacheで行われたすべてのログで新しい値がログに記録され、ログにはまだ変更されていない値が表示される理由を説明しています。彼らは現在2つの異なるオブジェクトを指しており、cacheが指し示しているオブジェクトの内容を変更すると、元のオブジェクトに何の影響も与えずにobj.cacheが指し示しています。

+0

ああ!ダー!私は 'cache = {}'がキャッシュを新しいオブジェクトに再割り当てしているとは思っていませんでしたが、今ではそれを指摘していることは非常に明確です。私はこれが単に「キャッシュ」と呼ばれるオブジェクトを空にしていると思っていました。これは今、完璧な意味を持ち、私の正気は回復しています。ありがとうございました。 – Mark

0

あなたのIIFEが実行された時点で、cacheobj.cacheに追加しました。そうでした。 obj.cacheIIFEの変数cacheへの参照を保持していません。しかし、reportpreload関数は、作成されたスコープ外で呼び出されたとしても、IIFEの変数cacheを使用しています。したがって、IIFE内のスコープへの参照は、obj.preloadおよびobj.report関数(これはクロージャが観察される場所です)では保持されますが、obj.cacheでは保持されません。

閉鎖がどのように観察され、行使されているかの詳細については、linkを参照してください。

関連する問題