关闭失败 - 即使在阅读了所有相关内容之后

时间:2011-09-26 13:50:35

标签: javascript closures

我有这个倒计时

fiddle here

我想在onload中进行以下工作,但我显然有关闭的问题

for (var o in myDates) {
  var myDate = myDates[o];
  var iid = o;
  funcs[o] = function() {
    var dateFuture = new Date();
    dateFuture.setSeconds(dateFuture.getSeconds()+myDate.durationInSecs);
    GetCount(dateFuture,iid);    
  }
  myDates[iid].tId = setTimeout("funcs['"+iid+"']()",myDates[o].delay*1000);
}

以下代码有效。 但它有一个隐式eval和2个全局变量,我想像上面的非工作代码一样循环


<html>
<head>
<script type="text/javascript">

var myDates = {
    d0: {
      durationInSecs: 5, 
      delay:0,
      repeat:false,
      duringMessage : " until something happens",
      endMessage    : " something happened",      
      repeatMessage : ""
    }, 
    d1: { 
      durationInSecs: 10, 
      delay:3,
      repeat:true,
      duringMessage : " until something else happens",
      endMessage    : " something else happened",
      repeatMessage : "This will repeat in 3"
    }
}
var funcs = {};

window.onload=function(){
  // the below could be done in a loop, if I was better in closures
  setTimeout(function() {
    funcs["d0"] = function() {
      var myDate = myDates["d0"];    
      var dateFuture0 = new Date();
      dateFuture0.setSeconds(dateFuture0.getSeconds()+myDate.durationInSecs);
      GetCount(dateFuture0,"d0");    
    }
    funcs["d0"]();
  },myDates["d0"].delay*1000);
  // ---------------
  setTimeout(function() {
    funcs["d1"] = function() {
      var myDate = myDates["d1"];
      var dateFuture1 = new Date();
      dateFuture1.setSeconds(dateFuture1.getSeconds()+myDate.durationInSecs);
      GetCount(dateFuture1,"d1");    
    }
    funcs["d1"]();    
  },myDates["d1"].delay*1000);
};


//######################################################################################
// Author: ricocheting.com
// Version: v2.0
// Date: 2011-03-31
// Description: displays the amount of time until the "dateFuture" entered below.

// NOTE: the month entered must be one less than current month. ie; 0=January, 11=December
// NOTE: the hour is in 24 hour format. 0=12am, 15=3pm etc
// format: dateFuture1 = new Date(year,month-1,day,hour,min,sec)
// example: dateFuture1 = new Date(2003,03,26,14,15,00) = April 26, 2003 - 2:15:00 pm



// TESTING: comment out the line below to print out the "dateFuture" for testing purposes
//document.write(dateFuture +"<br />");
//###################################
//nothing beyond this point
function GetCount(ddate,iid){
    dateNow = new Date();   //grab current date
    amount = ddate.getTime() - dateNow.getTime();   //calc milliseconds between dates
    delete dateNow; // is this safe in IE?

  var myDate = myDates[iid]; 
    // if time is already past
    if(amount < 0){
        document.getElementById(iid).innerHTML=myDate.endMessage;
        if (myDate.repeat) {
      setTimeout(funcs[iid],myDate.delay*1000);
      document.getElementById(iid).innerHTML=myDate.repeatMessage;
    } 
    }
    // else date is still good
    else{
        secs=0;out="";

        amount = Math.floor(amount/1000);//kill the "milliseconds" so just secs

        secs=Math.floor(amount);//seconds

        out += secs +" "+((secs==1)?"sec":"secs")+", ";
        out = out.substr(0,out.length-2);
        document.getElementById(iid).innerHTML=out + myDate.duringMessage;
        document.title=iid;
        setTimeout(function(){GetCount(ddate,iid)}, 1000);
    }
}

</script>
</head>
<body>
<div>
<span id="d0" style="background-color:red">!!</span>
<span style="float:right¨;background-color:green" id="d1">??</span>
</div>
</body>

1 个答案:

答案 0 :(得分:1)

你陷入了在循环中声明闭包的陷阱。内部函数关闭了变量 myDate和而不是的值。这是特别意外的,因为变量应该具有块范围而不是多次迭代(不是Javascript中的情况 - 一切都是函数范围)。

你可以通过一个闭包制造者功能来解决这个问题。这样,您可以创建一个新的变量实例,以便随意关闭。

<强> WRONG

var i;
for(i=0; i<xs.length; i++){
    something = function(){
        f(i);
    };
}
//all closures share the i variable and will have it
//be i=xs.length in the end. We don't want that.

确定

function make_handler(i){
    return function(){
        f(i);
    };
    //each call gets its own copy of i
}
var i;
for(i=0; i<xs.length; i++){
    something = make_handler(i);
}

或封闭制造商内联

var i;
for(i=0; i<xs.length; i++){
    something = (function(i){
        return function(){
            f(i);
        };
    }(i));
}