关闭

时间:2016-05-08 05:38:14

标签: javascript closures

变量cont在以下内容中丢失:

    __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:{}})我收到一条错误消息,指出cont未定义,而window.popSelectComponent的定义与预期相同。我试着更改cont的名字,我忽略了一些改变了价值的东西,但这也没有用。

在运行该函数之后,我检查了最初创建此闭包的上下文中的cont,并且仍然定义了cont,因此,就我所知,对象引用不会丢失。

1 个答案:

答案 0 :(得分: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具有您期望的块范围。保留<?php //update this to your DB connection details. $dbh = "localhost"; $dbn = "dbname"; $dbu = "dbuser"; $dbp = "dbpass"; $conn = mysql_connect($dbh,$dbu,$dbp) or die("Unable to connect do database."); mysql_select_db($dbn, $conn) or die("Unable to select database."); //Some vars for Order by and Limit. if (!isset($ordBy)){ $ordBy = 1; } if (!isset($ps)){ $ps = 0; } if (!isset($ord)){ $ord = 1; } if ($ord == 1){ $tOrder = "ASC"; } else { $tOrder = "DESC"; } //Tables drop-down $result = mysql_query("SHOW TABLES FROM $dbn") or die("Cannot list table names."); echo " <form name=\"table_browser\" action=\"".$PHP_SELF."\" method=\"GET\" > <select name=\"t\" onChange=\"javascript:submit();\"> <option>Select a table</option> "; while ($row = mysql_fetch_row($result)){ echo " <option value=".$row[0].">".$row[0]."</option>\n"; } echo " </select> </form>\n"; if (!isset($t)){ die("Please select a table"); } //Get number of rows in $t and then select $result = mysql_query("SELECT COUNT(*) FROM $t") or die("The requested table doesn't exist."); $total = mysql_result($result,0); $qry = "SELECT * FROM $t ORDER BY ".$ordBy." ".$tOrder." LIMIT ".($ps*20).",20 "; if (isset($qry)) { $result = mysql_query($qry) or die("The requested table doesn't exist."); $i = 0; while ($i < mysql_num_fields($result)) { $meta = mysql_fetch_field($result); if (!$meta) { echo "No information available on the table<br />\n"; } $name[$i] = $meta->name; $i++; } //Display table details echo "Rows ".($ps*20+1)." to ".((($ps+1)*20 < $total) ? (($ps+1)*20) : ($total))." of $total from table: <b>$meta->table</b>\n<br /><br />\n"; //Count results if ($ps > 0) { echo "<a href=\"browse.php?t=$t&ps=".($ps-1)."&ordBy=$ordBy&ord=$ord\">20 Previous</a> - "; } else { echo "20 Previous - "; } if ((($ps+1)*20) < $total ){ echo "<a href=\"browse.php?t=$t&ps=".($ps+1)."&ordBy=$ordBy&ord=$ord\">Next 20</a>\n"; } else { echo "Next 20\n"; } //Column names echo "<br /><br />\n<table>\n <tr>\n"; for ($j = 0; $j < $i; $j++){ echo " <td><b><a href=\"browse.php?t=$t&ps=$ps&ordBy=$name[$j]&ord=".(-$ord)."\">$name[$j]</a></b>"; if ($ordBy == $name[$j]) { echo "<img src=\"images/arrow$ord.gif\">"; } echo "</td>\n"; } echo " </tr>\n"; //Data while ($row = mysql_fetch_array($result)){ echo " <tr onmouseover=\"this.style.background='#DDDDDD'\" onmouseout=\"this.style.background=''\">"; for ($j = 0; $j < $i; $j++){ echo "<td>".$row[$name[$j]]."</td>"; } echo "</tr>\n"; } echo "</table>\n"; } mysql_close(); ?> 是为了向后兼容,但您不应在新代码中使用它。