2017-04-09 1 views
0

나는 클로저를 이해한다고 생각했지만 갑자기 뭔가 간단한 것이 작동하지 않는 것 같습니다.클로저가 상태 변경을 유지하지 않음

나는 클로저를 사용하여 싱글 톤을 만들었습니다. 여기에 매우 축소 된 버전입니다 :

Foobar = function() { 
     var data = null; 

     function init(obj) { 
      data = obj; 
     } 

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

는 싱글이기 때문에, 나는 내가 '초기화하기'함수를 호출 할 때, '데이터'의 값이 존재하는 유일한 객체에 변경 될 것으로 기대가, 그 값은 'currentValue'를 사용하여 이후의 검색에서 계속 사용할 수 있습니다. - '데이터'init 함수에 볼 수 있습니다, 그리고 그 변화하고 있음을 나는 파이어 폭스 (F12)에서이 코드를 단계별로 할 때,

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

를 내가 네 것을 볼 수 있습니다 여기에

내 테스트입니다 변수 'init'을 실행할 때. 그러나, init 함수를 빠져 나온 후 test의 두 번째 라인을 실행하기 위해 돌아 오면 'init'함수에 전달 된 객체의 복사본 대신 var 'test'에 null (싱글 톤이 생성되었을 때의 원래 값)이 할당됩니다 , 나는 예상했다.

누군가 내 혼란을 해결할 수 있습니까?

답변

1

난 당신이 here-- 즉 다른 두 가지를 가미하여 생각, 난 당신이 혼란 "자바 스크립트 클로저", "자바 스크립트가 참조로 객체를 전달"하고 점점 생각합니다.

기본 질문에 대답하려면 - 문제는 변수의 값을 인스턴스화에서 한 번만 반환하고 다시는 반환하지 않는 것입니다. 따라서 업데이트해도 아무런 변화가 없습니다. 대신,이 함수를 작성하는 경우 반환 값이, 당신은이 업데이트되는 것을 볼 것입니다 :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() {...}(); 

에서 시작, 글로벌 범위는, 아니 우 기준으로는 foobar를 등록 그래서 Foobar는 Immediately Invoked Functi가 나오기 전 어디에도 정의되어 있지 않습니다. 표현식 (IIFE).

두 번째 줄에는 IIFE가 실행 된 후 Foobar가 IIFE의 반환 된 개체에 아래 그림과 같이 할당되어 있습니다.

console.log(Foobar); // undefined 
var Foobar = function() {...}(); 
console.log(Foobar); // Object {currentValue: null, init: function} 
이 때 인생의 리턴 된 객체가 시각화

Click to show Diagram of Initial Foobar이어서

같은 경우 Foobar.init (ID {3});이 실행됩니다. Foobar의 init은 IIF의 init이라는 rhs 참조를 요청할 것입니다. 초기화는 데이터에 폐쇄을 가지고 있으며, 결국 데이터을 설정 {ID : 3}

Click to show Diagram of after Foobar.init

따라서

var test = Foobar.currentValue; 

가 초기 상태로 값이 여전히 명확하다.

우리의 기대를 충족 시키십시오. 여기에 적어도 두 가지 가능한 해결책이 있습니다 (anied). 폐쇄와 인생에서 다른 기능을 만들기

  1. 을 검색 을 위해 데이터 이상.
  2. 데이터을 새 개체에 할당하는 대신 IIFE의 직접 초기화 은 동일한 개체 자체를 조작합니다.
+0

다이어그램을 고맙게 생각합니다. 또한 버그를 수정하는 대신 질문에 대답 할 시간을 가졌습니다. – JackLThornton

관련 문제