Javascript jQuery-请向我解释闭包、变量上下文

Javascript jQuery-请向我解释闭包、变量上下文,javascript,jquery,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;

好吧,我不明白为什么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]未定义。意味着它无法访问#画布。。为什么???

这是因为在您的第一次调用中,您实际上正在创建一个函数对象,该对象将仅在加载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);

我想你搞错问题了。并不是您误解了变量上下文,而是您可能在声明canvas标记之前运行了javascript

下面的代码演示了这个问题。它将显示消息“canvasOne未定义!”,因为我们试图在声明之前访问
canvasOne
(注意
标记的位置)

我在这里创建了一个托管演示:(可编辑)


/* 
浏览器一看到下面这行代码就立即运行它。
由于“canvasOne”标记尚未声明,因此变量将未定义。
*/
变量canvasOne=$('#canvasOne')[0];
$(函数(){
//以下代码在整个文档完成加载后运行。
if(canvasOne==未定义){
警报('canvasOne未定义!');
}
否则{
canvasOne.getContext(“2d”).fillRect(5,5,15,15);
}
});
/* 
浏览器一看到下面这行代码就立即运行它。
但由于上面*声明了“canvasTwo”标记*,因此变量*不会*未定义。
*/
var canvasTwo=$('#canvasTwo')[0];
$(函数(){
//以下代码在整个文档完成加载后运行。
if(canvasTwo==未定义){
警报('canvasTwo未定义!');
}
否则{
canvasTwo.getContext(“2d”).fillRect(5,5,15,15);
}
});
$(函数(){
/*
以下代码在整个文档完成加载后运行。
因此,即使“canvastree”标记出现在代码后面,变量*不会*未定义。
*/
var canvastree=$(“#canvastree')[0];
if(canvastree==未定义){
警报('canvastree未定义!');
}
否则{
canvasThree.getContext(“2d”).fillRect(5,5,15,15);
}
});

Seb所说的是正确的。第一个不起作用,因为在您尝试获取画布对象时,它还没有实际加载。虽然您在回调中包装代码是正确的,但在上下文问题上是错误的。问题可能是javascript代码是在声明canvas标记之前运行的。我在回答中已经说明了这一点。谢谢。我只是在试验这东西的工作方式。我现在明白了。@ SEB对不起,如果我唠叨你,但是请考虑编辑你的答案来纠正或删除关于上下文的评论。除非我完全弄错了,否则它们只是不正确和误导。谢谢。@brian我真的不确定上下文问题;我相信我是对的,但现在我怀疑它,应该测试它@Rymn,你能告诉我们真正的问题是你在画布实际创建之前试图访问它吗?如果是这样,请将brian的答案标记为正确,而不是我的答案。谢谢
<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>