在JavaScript中为Google Closure编译器注释Singleton对象,或“危险使用全局此对象”警告

时间:2011-04-16 15:46:15

标签: javascript google-closure-compiler jsdoc

我正在使用ADVANCED_OPTIMIZATIONS编译级别的Google Closure Compiler,并开始注释我的构造函数,因为我收到了各种警告:

  

警告 - 危险使用全局此对象

对于我的'构造函数'类型函数,我会像这样注释它们:

/**
 * Foo is my constructor
 * @constructor
 */
Foo = function() {
   this.member = {};
}

/**
 * does something
 * @this {Foo}
 */
Foo.prototype.doSomething = function() {
   ...
}

这似乎工作正常,但是如果我有一个'singleton'对象不是用var myFoo = new Foo()构造的呢? 我在文档中找不到如何注释这种类型的对象,因为它的类型只是对象吗?

Bar = {
   member: null,
   init: function() {
      this.member = {};
   }
};

2 个答案:

答案 0 :(得分:9)

在Closure中创建单例的首选方法是这样的:

/** @constructor */
var Bar = function() { };
goog.addSingletonGetter(Bar);

Bar.prototype.member = null;

Bar.prototype.init = function() {
  this.member = {};
};

这允许单例的惰性实例化。像这样使用它:

var bar1 = Bar.getInstance();
var bar2 = Bar.getInstance();

bar1.init();
console.log(bar2.member);

请注意,这并不妨碍人们使用构造函数创建Bar的实例。

答案 1 :(得分:5)

这是完全潜在错误的类型,“危险使用此”会警告您。在您的示例中,Closure Compiler 可能尝试将您的代码“展平”为:

Bar$member = null;
Bar$init = function() { this.member = {}; };

注意:Closure Compiler当前不会压缩声明为全局对象的命名空间(即前面没有“var”关键字),因此您的代码现在仍然可以正常工作。但是,没有任何迹象表明它在将来的版本中不会这样做,并且您的代码会在没有警告的情况下突然中断。

当然,“Bar $ member”和“Bar $ init”将分别重命名为“a”和“b”。这称为“命名空间扁平化”或“属性折叠”。

您可以立即查看您的代码无法正常运行。在编译之前,如果你写:

Bar.init();

this会引用Bar。但是,编译后它变为:

Bar$init();

this将不再引用Bar。相反,它指的是全局对象。

这是编译器试图警告您以这种方式使用“this”是“危险的”的方式,因为“this”可能会被更改为引用“global”对象。这就是警告的真正含义。

简而言之,不要这样做。这种类型的编码风格会产生非常难以追踪的错误。

以这种方式修改代码:

var Bar = {    // Closure Compiler treats globals and properties on global differently
  member: null,
  init: function() { Bar.member = {}; }
};

或使用闭包:

var Bar = (function() {
  var member = null;
  return {
    init: function() { member = {}; }
  };
})();

在高级模式下使用Closure Compiler时,不要试图通过注释它们来消除警告。警告是有原因的 - 他们试图警告你什么。