2016-05-08 88 views
0

失去了本地變量中,續被丟在以下幾點:在封閉

__factory.setupMenu = function(cont,input,multiSelect,exclusive,popMenu){    
     var __menu = {multiSelect:multiSelect}; 
     spotter.events.setEventTrigger(input,'change'); 
     __menu.exclusive = {inputs:[],values:exclusive||[],simpleValues:[]}; 
     alert(cont);//<-- is defined here 
     window.popSelectComponent= cont;//<-- saved it globally to test reference 

     return function(ajaxResult){ 
      var data = ajaxResult.template.response||[]; 
      var info = {},l=data.length; 
      while(--l > -1){ 
       info[String(data[l].value)] = data[l].abbr||data[l].name; 
      } 

      var textTarget; 
      alert(window.popSelectComponent);//<-- this is defined as expected 
      alert(cont);//<-- is now undefined 
      alert(input);//<-- this is defined as expected 
      if(!(textTarget = cont.querySelector('[data-pop-selected]'))){textTarget = cont;} 

if(!input.popSelectTemplate){ 
       spotter.data.bindElementToInput(textTarget,input,function(content){ 
        content = content.split(','); 
        var l=content.length; 
        while(--l > -1){ 
         content[l] = info[content[l]]; 
        } 
        content = content.join(','); 
        return (content.length ? content : 'ignore'); 
       }); 
      } 
      else{ 
       var cont = document.createElement('SPAN');//<-- PROBLEM IS CAUSED HERE. HOISTING IS CAUSING CONT TO BE UNDEFINED AT CLOSURE START 
       cont.className="multi-select"; 
       cont.appendChild(cont); 

       //removal function 
       var remove = (function(input){ 
        return function(e){ 
         var evt = e ? e:window.event; 
         if (evt.stopPropagation) evt.stopPropagation(); 
         if (evt.cancelBubble!=null) evt.cancelBubble = true; 
         if(input.value !== input.spotterPopSelectDefaultValue){ 
          input.value = input.value.removeListValue(this.getAttribute('data-id'),','); 
          spotter.deleteElement(this); 
          if(input.value === '' && input.value !== input.spotterPopSelectDefaultValue){ 
           input.value = input.spotterPopSelectDefaultValue; 
           input.eventTriggers['pop-select-change'](); 
          } 
         } 
        }; 
       }(input)); 

       input.spotterPopMenuOptions = __menu; 
       input.addEventListener('pop-select-change',(function(cont, info, template){ 
        return function(){ 
         var HTML = ''; 
         this.value.split(',').forEach(function(val){ 
          HTML += template.replace('$[ID]', val).replace('$[NAME]', info[val]); 
         }); 
         cont.innerHTML = HTML; 
         spotter.castToArray(cont.children).forEach(function(el){ console.log('option el',el); el.addEventListener('click',remove,false); }); 

         console.log('input.spotterPopMenuOptions',input.spotterPopMenuOptions); 
        }; 
       }(cont, info, input.popSelectTemplate.innerHTML)),false); 
      } 
.... 

所以運行var func = __factory.setupMenu(...)({template:{}})我收到了,而window.popSelectComponent的定義如下預期續未定義的錯誤消息。我嘗試改變cont的名字,我想我忽略了一些正在改變價值的東西,但是這也沒有奏效。

運行該函數之後,我在上下文中檢查了cont,最初創建了這個閉包,而cont仍然被定義,所以它不是一個對象引用丟失的問題,據我所知。

+0

試着'console.log(...)'而不是使用alert。它會讓你的生活更輕鬆,你不會後悔的。 – RobB

+0

您的代碼*實際*在該函數內部具有alert(cont),還是在調試時嘗試在控制檯中運行該代碼?我懷疑有這樣的事情發生:http://stackoverflow.com/a/21918024/1715579 –

+0

我只添加警報來測試值,因爲我目前正在運行的console.log消息的數量巨大:P –

回答

0

也許一個高度簡化的例子會使問題更加明顯:

var outer = function(theVariable) { 
    console.log("In the outer function, theVariable is", theVariable); 
    var inner = function() { 
    console.log("In the inner function, theVariable is", theVariable); 
    if (false) { 
     var theVariable = 2; 
    } 
    }; 
    inner(); 
} 
outer(1) 
In the outer function, theVariable is 1 
In the inner function, theVariable is undefined 

正如你所看到的,事實上,具有相同名稱不同的變量已聲明(即使未初始化)在內函數隱藏了外部函數中正確初始化的變量,否則這些變量可見。

您可能會認爲,因爲變量是在塊中聲明的,所以不會影響函數的其他部分。不,var是函數作用域,而不是作用域作用域。

此漏洞已在現代版本的Javascript中解決,並且var關鍵字已被let取代,它具有您期望的塊範圍。 var保留向後兼容性,但不應在新代碼中使用它。

+0

我懷疑他認爲這個塊是相關的,但僅僅是''var'語句是在'console.log'之後執行的。提升使得'var'聲明的位置無關緊要。 – Barmar