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

发布于 2024-11-02 09:07:51 字数 587 浏览 3 评论 0原文

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

警告 - 全局 this 对象的危险使用

对于我的“构造函数”类型函数,我将这样注释它们:

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

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

这似乎工作正常,但是如果我有一个不是用 var myFoo = new 构造的“单例”对象怎么办Foo(); 我在文档中找不到如何注释这种类型的对象,因为它的类型只是对象,对吧?

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

I'm working with the Google Closure Compiler in ADVANCED_OPTIMIZATIONS compilation level and have started to annotate my constructors because I get all kinds of warnings:

WARNING - dangerous use of the global this object

For my 'constructor' type functions I'll annotate them like this:

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

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

That seems to work fine, however what if I have a 'singleton' object that isn't constructed with var myFoo = new Foo();
I couldn't find in the documentation how to annotate this type of object because its type is just object right?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

野の 2024-11-09 09:07:51

在 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 的实例。

The preferred way of creating singletons in Closure is like this:

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

Bar.prototype.member = null;

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

This allows for lazy instantiation of the singleton. Use it like this:

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

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

Keep in mind that this doesn't prevent people from using the constructor to create instances of Bar.

身边 2024-11-09 09:07:51

正是“危险使用此”警告您的潜在错误类型。在您的示例中,闭包编译器可能尝试将您的代码“扁平化”为:

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

注意:闭包编译器当前不会扁平化声明为全局对象的命名空间(即没有“ var”关键字在前面),所以您的代码现在可能仍然有效。但是,不知道在未来的版本中它不会这样做,并且您的代码会在没有警告的情况下突然中断。

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

您可以立即发现您的代码不再正常工作。在编译之前,如果你写:

Bar.init();

this 将引用 Bar。然而,编译后它变成:

Bar$init();

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

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

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

以这种方式修改代码:

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 = {}; }
  };
})();

在高级模式下使用闭包编译器时,不要尝试通过注释来消除警告。警告的出现是有原因的——它们试图警告你一些事情。

This is exactly the type of potential bug that "dangerous use of this" warns you against. In your example, the Closure Compiler may try to "flatten" your code to:

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

NOTE: The Closure Compiler currently will not flatten a namespace that is declared as a global object (i.e. without the "var" keyword in front), so your code may still work now. However, there is no telling that it won't do that in a future version and your code will suddenly break without warning.

Of course, then "Bar$member" and "Bar$init" will be renamed to "a" and "b" respectively. This is called "namespace flattening" or "collapsing of properties".

You can immediately see that your code no longer works correctly. Before compilation, if you write:

Bar.init();

this will refer to Bar. However, after compilation it becomes:

Bar$init();

this will no longer refer to Bar. Instead it refers to the global object.

This is way the compiler is trying to warn you that using "this" in such a way is "dangerous", because "this" may be changed to refer to the "global" object. That's the true meaning of the warning.

In short, DO NOT DO THIS. This type of coding style creates bugs that are very difficult to track down.

Modify your code this way:

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

or use a closure:

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

When using the Closure Compiler in Advanced Mode, do not try to get rid of warnings by annotating them away. Warnings are there for a reason -- they try to warn you about something.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文