2017-04-09 10 views
0

私は閉鎖を理解したと思っていましたが、突然何か単純なことが働いていないようです。閉鎖状態を保持しない

私はクロージャを使ってシングルトンを作成しました。

Foobar = function() { 
     var data = null; 

     function init(obj) { 
      data = obj; 
     } 

     return { 
      init: init, 
      currentValue: data 
     } 
    }(); 

それはシングルトンですので、私は、私は「initの」関数を呼び出すとき、「データ」の値が存在する唯一のオブジェクトに変更されることを期待する:ここでは非常に縮小さバージョンがありますその値は引き続き検索で 'currentValue'を使用して使用できるようになります。ここで

は私のテストで:

Foobar.init({id:3}); 
    var test = Foobar.currentValue; 

私は、Firefox(F12)でこのコードをステップ実行すると、私はそうすることを見ることができます - 「データが」init関数に表示され、それはそれを変更していること私が 'init'を実行すると変数になります。ただし、init関数を終了して2行目のテストを実行すると、 'init'関数に渡されたオブジェクトのコピーではなく、var 'test'にnull(シングルトンが作成されたときの元の値)が割り当てられます、 私の期待通りに。

誰かが私の混乱を解消できますか?

答えて

1

は、私はあなたがhere--つまり二つの異なるものをconflatingていると思う、私はあなたが混乱し、「Javascriptのクロージャ」「Javascriptが参照によってオブジェクトを渡す」となっていると思います。

主な質問に答えるには、変数の値をインスタンシエーション時に1回返し、その後はまったく返さないことが問題です。更新することで何も変わることはありません。代わりに、あなたは関数を作成した場合戻り値は、あなたはそれが更新されて表示されますこと:dataオブジェクトとして初期化された場合NOW

Foobar = function() { 
 
     var data = null; 
 

 
     function init(obj) { 
 
      data = obj; 
 
     } 
 

 
     function getCurrentValue() { 
 
      return data; 
 
     } 
 
    
 

 
     return { 
 
      init: init, 
 
      getCurrentValue: getCurrentValue 
 
     } 
 
    }(); 
 
    
 
    Foobar.init({id:3}); 
 
    console.log(Foobar.getCurrentValue());

を、そしてあなたinitは、単純にそのオブジェクトを何らかの方法で拡張するだけでしたが、そのプロパティ自体は、ライフサイクル全体を通して常に同じオブジェクトを参照するため、最初の例のように更新されます。

Foobar = function() { 
 
     var data = {}; 
 

 
     function init(obj) { 
 
      data.id = obj.id; 
 
     } 
 

 
     return { 
 
      init: init, 
 
      currentValue: data 
 
     } 
 
    }(); 
 
    
 
    Foobar.init({id:3}); 
 
    console.log(Foobar.currentValue);

+0

SOは、感謝しないと言っていますが、このケースでは、あまりにも何度も、ちょっとした例や特殊な状況でバグを解決することに焦点を当てています。それが次の人を助けることに失敗し、彼らは実際の質問への一般的な答えを得るためにもう一度質問をすると、重複した質問のためにうなずく。あなたは実際に質問に答えて、「バグを修正する」よりも何かを教えてくれました。これにより、将来間違いが繰り返される可能性は低くなります。このような種類の答えが、私がそれを評価する理由です。 – JackLThornton

1

問題は、返されたオブジェクトにデータを配置すると、関数が最初に実行されたときに値が保存されることです。これはnullです。

データ変数の現在の値を読み取るためには、currentValueはinitのような関数でなければなりません。

Foobar = function() { 
     var data = null; 

     function init(obj) { 
       data = obj; 
     } 

     function currentValue() { 
       return data; 
     } 

     return { 
       init: init, 
       currentValue: currentValue 
     } 
}(); 
console.log(Foobar); 
Foobar.init({id:3}); 
var test = Foobar.currentValue(); 
console.log(Foobar,test); 
1

ステートメントが最初の行で

var Foobar; 
Foobar = function() {...}(); 

に分けることができる

var Foobar = function() {...}(); 

から出発し、グローバルスコープは、無RHS参照してfoobarに登録FoobarはImmediately Invoked Functiの前のどこにでも定義されていません式(IIFEs)について。

2行目で、IIFEが実行された後、FoobarはIIFEの返されたオブジェクトに以下のように割り当てられます。場合Foobar.init({ID:3})この時点で生命維持の返されたオブジェクトは、その後

Click to show Diagram of Initial Foobar

として視覚化することができ

console.log(Foobar); // undefined 
var Foobar = function() {...}(); 
console.log(Foobar); // Object {currentValue: null, init: function} 

が実行されます。 Foobarのinitは、IIFのinitであるrhsの参照を求めます。 initは、データ上の閉鎖を持って、最終的に、{ID:3} データを設定するため

var test = Foobar.currentValue; 

Click to show Diagram of after Foobar.init

依然としてはっきり初期状態としてヌル値です。

私たちの期待に応える。前述のように、少なくとも2つの可能な解決方法がここにあります(anied)。それらを取得 するためにデータ以上の閉鎖と生命維持に別の関数を作成する

  1. データを新しいオブジェクトに代入する代わりに、IIFEの直接の初期化 は同じオブジェクト自体を操作します。
+0

ダイアグラムに感謝します。バグを修正するだけではなく、質問に答える時間もかかっています。 – JackLThornton

関連する問題