2

过去我再次遇到过这个问题,我使用了全局变量,但我想知道还有什么其他方法可以处理它。

代码来自我目前正在玩的一个 html5 画布教程。

var x = 150;
var y = 150;
var dx = 2;
var dy = 4;
var ctx;

function init() {
  ctx = $('#canvas')[0].getContext("2d");
  return 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;
}

init();

我能做些什么来避免使用全局变量?

4

4 回答 4

4

您可以使用模块模式 - 这是提供封装的一种巧妙方式:

var app = app || {};
app = (function () {
  var x = 150; // all these variables are private
  var y = 150;
  var dx = 2;
  var dy = 4;
  var ctx;

  var draw = function() { // this method is private
    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;
  };

  return {
    init: function() { // this method is public
      ctx = $('#canvas')[0].getContext("2d");
      return setInterval(draw, 10);
    }
  }
}());

app.init(); // init() is public, but all the other vars and functions are not

在http://addyosmani.com/largescalejavascript/#modpattern了解更多信息。

于 2012-10-13T19:37:06.307 回答
3

您可以使用一个对象,如此处所示

myObj = {
    x: 150,
    y: 150,
    dx: 2,
    dy: 4,
    ctx: null,
    init: function() {
        this.ctx = $('#canvas')[0].getContext("2d");
        return setInterval((function(a){return function(){a.draw()}})(this), 10);
    },
    draw: function() {
        this.ctx.clearRect(0,0,300,300);
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.y, 10, 0, Math.PI * 2, true);
        this.ctx.closePath();
        this.ctx.fill();
        this.x += this.dx;
        this.y += this.dy;
    }
}

myObj.init();

重要信息完全披露,此代码无法按原样运行。虽然我坚持我的一般方法,但 setInterval 仍然需要传递正确的上下文。我已经修复了我的答案以反映上述内容,并在小提琴链接中添加了一个工作示例。如果上下文传递让您感到困惑,请使用其他方法。

于 2012-10-13T19:35:49.560 回答
1

将它们作为参数传递,并返回修改后的它们:

function init() {
  var x = 150;
  var y = 150;
  var dx = 2;
  var dy = 4;
  var ctx = $('#canvas')[0].getContext("2d");
  return setInterval(function() {
    var temp = draw(x, y, dx, dy, ctx);
    x = temp.x;
    y = temp.y;
  }, 10);
}

function draw(x, y, dx, dy, ctx) {
  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;
  ret = {};
  ret.x = x;
  ret.y = y;
  return ret;
}

(我不完全确定需要传递什么;如果可以,请少传递以减少耦合。)

但是,此解决方案不如@Asad 提出的更类似于类的方法。

于 2012-10-13T19:35:28.573 回答
1

将所有内容包装在一个对象或一个负责全局变量的 IIFE 中是很诱人的,而且确实很容易,但这并没有真正为聚会带来任何新东西。我建议一个简单的闭包,其中所有变量都设置在init函数内。在这个函数中,我们定义了draw函数,以便该函数可以访问闭包变量。由于该函数仅用于设置间隔,因此我省略了名称,因为在此闭包中根本不需要命名函数。

var init = function()
{
    var x, y, dx, dy, ctx = document.getElementById('canvas').getContext('2d');
    return setInterval(function()
    {
        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;
    },10);
};
var iv = init();//<-- best off storing the interval somewhere
//... stop drawing:
clearInterval(iv);

仅此而已。

于 2012-10-13T19:49:01.047 回答