Сбой закрытия - даже после прочтения всего об этом - PullRequest
0 голосов
/ 26 сентября 2011

У меня есть этот отсчет

скрипка здесь

Я бы хотел сделать следующую работу в 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 Ответ

1 голос
/ 26 сентября 2011

Вы попали в ловушку объявления замыкания внутри петли. Внутренняя функция всегда закрывает переменную myDate и не над своим значением. Это особенно неожиданно, поскольку предполагается, что переменные имеют область видимости блока и не сохраняются в течение нескольких итераций (не так в Javascript - все является областью действия функции).

Вы можете обойти это, имея функцию создания замыканий. Таким образом, вы можете создать новый экземпляр переменной для закрытия по желанию.

НЕВЕРНО

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.

OK

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));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...