如何重写此代码以避免使用全局变量?

时间:2012-10-13 19:30:50

标签: javascript

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

代码来自我现在正在玩的an html5 canvas tutorial

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 个答案:

答案 0 :(得分: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了解详情。

答案 1 :(得分:3)

您可以使用对象,如图here

所示
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正确的上下文。我已经修复了我的答案以反映上述内容,并为小提琴链接添加了一个工作示例。如果上下文传递让您感到困惑,请使用其他方法。

答案 2 :(得分: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提出的方法。

答案 3 :(得分: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);

这就是它的全部。