3

我正在为 Javascript 创建一个游戏引擎,或者更像是一个包含有用类和函数的大型库。我计划将它用于服务器端和客户端的一些科学模拟,因此功能范围将相当广泛,但它总是围绕虚拟世界(例如游戏)。

不过,我不知道如何把它包起来。如果我只提供所有的类,它会污染全局命名空间,这是非常糟糕的。我可以将所有东西都放在一个对象中,作为命名空间吗?框架本身应该是一个可以实例化的类吗?

如果选择了后一个选项,我如何处理类中的类(构造函数)?

var Engine = function()
{
    this.someVar = 4;
}

Engine.prototype.Scene = function()
{
    this.entities = [];
    //What if the scene object needs some classes that are in the engine? How does it get it's parent engine object?
}

Engine.prototype.Scene.prototype.render = function()
{
    //"this" should now represent an instance of a scene. But how can I get someVar from the engine? How can I traverse up in the hierarchy of classes?
}
4

2 回答 2

2

我更喜欢使用有时被称为“揭示模块”(...模式)的东西。看起来像:

var Engine = (function($)
{
    $ = $ || {};
    var someVar = 4;

    $.Scene = function()
    {
        this.entities = [];
    }

    $.Scene.prototype.render = function()
    {
        // this function can access someVar just fine because of JavaScript's scoping rules
    }

    return $;
})(Engine);

这使用所谓的立即调用函数表达式(以下称为IIFE)在 Engine 对象内形成一个闭包。由于JavaScript 对范围的处理, IIFEsomeVar中定义的任何函数都可以访问。someVar但是,这意味着如果要引用someVar您在 IIFE 中定义的函数,则没有函数可以定义自己的函数。

魔术来自 return 语句。您可以看到返回了一个对象,并且在此对象中您必须定义任何您想要“公开”的内容。

然后可以通过 访问构造函数、实用程序方法等Engine.Scene,这很好地为您的代码命名空间。

至于$参数,这样您就可以传递Engine给每个文件中的函数,添加一些方法/属性/构造函数(如果不存在则创建一个新的),然后将返回值传递给另一个 IIFE 以进一步扩张。

这是许多流行的 JavaScript 框架中使用的方法,包括jQuerydojoLimeJS


场景.js:

var Engine = (function ($) {
  // this creates a new object if Engine is undefined in the 
  // invocation below, and keeps the old object otherwise.
  // alternatively: if ($ === undefined) { $ = new Object; }
  $ = $ || {};

  $.foo = "foo";
  $.Scene = function () {
    // blah blah
  }

  // Engine holds either a newly created object,
  // or the old one if it was already defined
  return $;
})(Engine);

sprite.js:

var Engine = (function ($) {
  $ = $ || {};

  $.Sprite = function () {
    // totally works
    this.bar = $.foo;
  }

  return $;
})(Engine);

然后,您可以将它们与以下内容一起使用:

<script type="text/javascript" src="bar.js"></script>
<script type="text/javascript" src="foo.js"></script>
<script type="text/javascript">
  var mySprite = new Engine.Sprite;
  var myScene = new Engine.Scene;
</script>

你可以$用任何你喜欢$$的、常见的或聪明的代替。它只是您要添加到的全局对象的占位符。

于 2012-07-30T09:23:01.817 回答
0

我认为你不需要甚至不应该那样组织你的课程。即使 Scene 和 Engine 类是相关的,Scene 类也不必是 Render 的子类。改为使用平面类层次结构,这将更容易维护和扩展。

最后,您确实应该将所有这些类放在同一个命名空间下,以免污染全局命名空间。

// Define the namespace only if it doesn't already exist. That
// way you can split the definition of your classes in various
// files, without having to worry in which order they are loaded.
if (typeof gameEngine === 'undefined') gameEngine = {};

gameEngine.Engine = function()
{
    this.someVar = 4;
}

gameEngine.Scene = function()
{
    this.entities = [];
}

// Add a new function to define which
// scene the Engine should render:
gameEngine.Engine.prototype.setScene = function(scene)
{
    this.scene = scene;
}

gameEngine.Engine.prototype.render = function()
{
    // render this.scene
}
于 2012-07-30T09:17:11.590 回答