jQuery-请向我解释Closure,变量上下文

时间:2009-05-12 04:30:56

标签: javascript jquery

好的,所以我不明白为什么Firefox会说$(“#canvas”)[0] .getContext('2d');未定义。我把它放在函数之外,这样所有函数都可以访问它,但是这里的ctx仍未定义。

(function($) {
        // Undefined
        var ctx = $('#canvas')[0].getContext("2d");
        var x = 150;
        var y = 150;
        var dx = 2;
        var dy = 4;
        $(function() {
            setInterval(draw, 10);
        })
        function draw() {
            ctx.clearRect(0,0,300,300);
            ctx.beginPath();
            ctx.arc(x,y,10,0,Math.PI*2,true);
            ctx.closePath();
            ctx.fill();
            x+=dx;
            y+=dy;
        }
    })(jQuery);

但是,当我将ctx的位置转移到未命名的函数时,ctx未定义:

(function($) {
        var ctx;
        var x = 150;
        var y = 150;
        var dx = 2;
        var dy = 4;
        $(function() {
              //Not Undefined
            ctx = $("#canvas")[0].getContext('2d');
            setInterval(draw, 10);
        })
        function draw() {
            ctx.clearRect(0,0,300,300);
            ctx.beginPath();
            ctx.arc(x,y,10,0,Math.PI*2,true);
            ctx.closePath();
            ctx.fill();
            x+=dx;
            y+=dy;
        }
    })(jQuery);

第一个代码有什么问题?我的意思是var ctx被声明在顶部。这样就可以使它成为一个全局变量。嗯,我得到的错误是$(“#canvas”)[0]未定义。意味着它无法访问#canvas ..为什么??

2 个答案:

答案 0 :(得分:4)

我认为你错了这个问题。这并不是说你误解了你的变量上下文,但可能是在宣布了canvas标签之前你正在运行javascript

以下代码演示了此问题。它将显示消息“canvasOne未定义!”因为我们在声明之前尝试访问canvasOne(请注意<canvas>标记的位置。)

我在此处创建了一个托管演示:http://jsbin.com/afuju(可通过http://jsbin.com/afuju/edit进行编辑)

<html>
  <head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
  </head>
  <body>
    <script>
      /* 
        The following line of code is run as soon as the browser sees it.
        Since the "canvasOne" tag is not declared yet, the variable will be undefined.
      */
      var canvasOne = $('#canvasOne')[0];

      $(function() {
        // The following code is run after the whole document has finished loading.
        if (canvasOne === undefined) {
          alert('canvasOne is undefined!');
        }
        else {
          canvasOne.getContext("2d").fillRect(5, 5, 15, 15);
        }
      });
    </script>
    <canvas id="canvasOne"></canvas>



    <canvas id="canvasTwo"></canvas>

    <script>
      /* 
        The following line of code is run as soon as the browser sees it.
        But since the "canvasTwo" tag *is* declared above, the variable will *not* be undefined.
      */
      var canvasTwo = $('#canvasTwo')[0];

      $(function() {
        // The following code is run after the whole document has finished loading.
        if (canvasTwo === undefined) {
          alert('canvasTwo is undefined!');
        }
        else {
          canvasTwo.getContext("2d").fillRect(5, 5, 15, 15);
        }
      });
    </script>



    <script>
      $(function() {
        /*
          The following code is run after the whole document has finished loading.
          Hence, the variable will *not* be undefined even though the "canvasThree" tag appears after the code.
        */
        var canvasThree = $('#canvasThree')[0];
        if (canvasThree === undefined) {
          alert('canvasThree is undefined!');
        }
        else {
          canvasThree.getContext("2d").fillRect(5, 5, 15, 15);
        }
      });
    </script>

    <canvas id="canvasThree"></canvas>
  </body>
</html>

答案 1 :(得分:3)

这是因为在您的第一次调用中,您实际上正在创建一个Function对象,该对象仅在DOM加载后才会在另一个上下文中处理。

当页面中的所有元素都已加载时,将调用匿名函数,因此调用者将是一个jQuery核心函数,其上下文与您在此编码的函数完全不同。

我建议将所有内容包装在$()调用中,这样就可以了:

(function($) {
        $(function() {
            var ctx = $("#canvas")[0].getContext('2d');
            var x = 150;
            var y = 150;
            var dx = 2;
            var dy = 4;

            setInterval(draw, 10);

            function draw() {
                    ctx.clearRect(0,0,300,300);
                    ctx.beginPath();
                    ctx.arc(x,y,10,0,Math.PI*2,true);
                    ctx.closePath();
                    ctx.fill();
                    x+=dx;
                    y+=dy;
            }
        });
})(jQuery);