【问题标题】:Is this the correct example of a closure in Javascript?这是 Javascript 中闭包的正确示例吗?
【发布时间】:2016-02-12 18:13:29
【问题描述】:

我正在阅读一本关于 Javascript 的书,并尝试了其中的一个闭包示例。

function animateIt(id) {
   var elem= document.getElementById(id);
   var tick=0;

   var timer=setInterval(function() {
     if (tick<100) {

       elem.style.left = tick+"px";
       elem.style.top=tick+"px";
       tick++;
     } else {
       clearInterval(timer);
       assert(tick==100, "Tick Accessed and has value:- "+ tick);
       assert(elem, "element accessed");
       assert(timer, "timer accessed")
     }
   }, 10);
 }
 animateIt(box);      

但是 timer 中的函数无法访问 elem、tick 等,而书上说它应该可以访问它们。 请告诉我。

【问题讨论】:

  • box 定义在哪里?
  • “不能访问 elem、tick 等” 你怎么知道你不能访问它们?您是否在控制台上收到错误说它们不存在?我在代码中看到的唯一问题是它可能在id 标识的元素存在之前运行,所以elem 最终会成为null
  • @Oriol 应该用console.assert 代替assert 吗?传递给 assert 的第一个参数也应该是 Boolean developer.mozilla.org/en-US/docs/Web/API/console/assert 吗? jsfiddle.net/r2u5r8f9/1
  • @guest271314 是的,对assert 的调用会抛出,但这并不重要。我的意思是动画作品。

标签: javascript closures


【解决方案1】:

这可以被认为是闭包,函数animateIt包含变量idelem,所以如果你为不同的id运行animateIt它会正常工作。

【讨论】:

    【解决方案2】:

    您没有给出整个代码(框,断言),但似乎有关闭。 假设现在执行了函数 animateIt,则创建了一个新的执行上下文,以及诸如 tick 和 elem 之类的变量。

    当执行到这里时:

    var timer=setInterval(function() {
    

    创建了一个新函数。这是一个匿名函数。它是 setInterval 中的函数,并且它引用了它的父函数(animateIt) 范围对象。范围对象包含变量 - elem,tick。它具有对范围对象的引用,因为函数 anon 在词法上位于函数 animateIt 内。父级本身包含诸如

    之类的变量
    var elem= document.getElementById(id);
    var tick=0;
    

    这些变量被您的匿名函数(在 setInterval 内)引用,因为它们位于 animateIt 的范围对象内,并且您的匿名函数引用了它。

    一旦 animateIt 函数执行上下文结束,您通过 setInterval 传递给事件队列的函数会因为 setInterval 继续执行和关闭,并且它可以访问曾经“存在”的函数的 var (在执行期间),但现在没有。该函数称为 animateIt,而闭包将这些 vars(tick,elem) 保存在内存中。

    【讨论】:

      【解决方案3】:

      在未命名函数调用(setInterval 包含未命名函数)中可见的刻度变量是一个闭包。

      每个函数调用都会创建闭包。

      //source function which contain the variable: 
      //lets consider it as a global function call
      var tick=0;
      
      (function() {
          //target function
          //1. closure is created on function call and 
          //2. another characterictic of closure is that 
          // source function must be parent of the target function
          console.log(tick); //so closure is equal to implicit parametrization
          //on target function call
      }());
      

      在前面的示例中,我正在调用一个函数,一个变量被隐式添加到目标函数调用的内部“范围”。

      我为“闭包”使用了另一个名称(函数调用的隐式参数化)。

      function animateIt(id) {
      
          var timer=setTimeout(function() {
              id="wow"; //important! there is no var keyword, so the outer variable is changed
          }, 1000);
      
         var timer=setInterval(function() { //on each function call a closure is created
           // in your case a built in function calls the function and 
           // on each call a closure is created
           console.log(id)
         }, 10);
      
       }
      
       animateIt("test");
      

      【讨论】:

      • 不,在评估函数定义时会创建一个闭包;在定义时捕获词法范围。你所拥有的就是一个范围。
      • 函数体的每次求值都会创建一个新作用域,函数调用会在其中绑定参数和局部变量。
      • 我认为“范围”描述了像 c# 这样的语言更好的变量存储,因为下面的表达式 { } 肯定会清除内部变量(非函数式语言)。所以我认为我们不应该在 javascript 中使用“范围”术语,因为闭包是在函数调用时创建的(这是函数式语言行为)。例如stackoverflow.com/a/111111/1145224 示例 7。Dan,你怎么看?
      • @DanD。 ,你能参考一下你的范围和闭包定义的书或博客吗?
      • 嗯,lexical environment 是 ES5 标准使用的术语。
      猜你喜欢
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 2013-12-04
      • 2019-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多