Javascript googleclosure库中的名称空间问题

Javascript googleclosure库中的名称空间问题,javascript,google-closure-compiler,google-closure-library,javascript-namespaces,Javascript,Google Closure Compiler,Google Closure Library,Javascript Namespaces,在前面提到的教程中,模块提供的名称空间是: goog.provide('tutorial.notepad.Note') 但我想知道为什么不是这样: google.provide('tutorial.notepad') 因为,根据下述规则: tutorial = tutorial || {}; tutorial.notepad = tutorial.notepad || {}; tutorial.notepad.Note = tutorial.notepad.Note || {}; 如果我们只是

在前面提到的教程中,模块提供的名称空间是:

goog.provide('tutorial.notepad.Note')

但我想知道为什么不是这样:

google.provide('tutorial.notepad')

因为,根据下述规则:

tutorial = tutorial || {};
tutorial.notepad = tutorial.notepad || {};
tutorial.notepad.Note = tutorial.notepad.Note || {};
如果我们只是提供:

google.provide('tutorial.notepad')那么,我们已经有了:

tutorial = tutorial || {};
tutorial.notepad = tutorial.notepad || {};
我们可以在其中添加属性
Note

tutorial.notepad.Note = function() {};
因此,我的问题是:

为什么不直接声明
goog.provide('tutorial.notepad')
,然后使用它来包含顶级
,而建议对我觉得多余的每个
类使用
goog.provide('tutorial.notepad.Note')

拥有
google.provide('tutorial.notepad')
在该命名空间的“依赖项树”中创建一个条目,但它不为类
tutorial.notepad.Note创建条目。如果在示例代码中手动创建
tutorial.notepad.Note
,则不会激活闭包编译器机制以将类
tutorial.notepad.Note
包含到闭包编译器使用的命名空间依赖项树中

原因是闭包编译器使用
goog.provide
来设置依赖关系树,用于确定要加载的名称空间以及加载顺序

通过不使用
goog.provide
,而是使用您显示的代码模拟其效果,编译器不会了解类
Note
,也不会了解它如何适应名称空间和类及其依赖关系树

有两种方法可以运行基于闭包编译器的代码:已编译和未编译。其中每一个都以不同的方式构建和使用命名空间依赖关系树:

  • 未编译闭包编译器的一大优点是,您可以运行所有未编译的代码。该过程中的一个必要步骤是使用
    depswriter.py
    ,这是一个Python程序,它读取所有源文件(查找
    goog.provide
    goog.require
    调用),并生成一个文件
    deps.js
    。该
    deps.js
    文件是名称空间依赖树的体现。下面是我的项目的
    deps.js
    文件中的一行示例(共333行):

    goog.addDependency('../../../src/lab/app/ViewPanner.js',
      ['myphysicslab.lab.app.ViewPanner'], ['myphysicslab.lab.util.DoubleRect',
       'myphysicslab.lab.util.UtilityCore', 'myphysicslab.lab.util.Vector',
       'myphysicslab.lab.view.CoordMap', 'myphysicslab.lab.view.LabView'], false);
    
当我在未编译状态下运行代码时,有一个
标记运行
deps.js
脚本。这样做会导致创建命名空间依赖关系树的内存版本,该版本可由
goog访问。require
在运行时加载该特定类所需的任何其他文件

  • 编译的编译器(一个Java程序)在编译过程中所做的事情与上面描述的差不多。不同之处在于,生成的命名空间依赖树仅在编译过程中用于确定类的定义顺序、需要什么等。编译完成后,命名空间依赖树将被丢弃
参考资料:


回应你的评论:

为什么不直接声明
goog.provide('tutorial.notepad')
,然后使用它来包含顶级
,而建议对我觉得多余的每个
类使用
goog.provide('tutorial.notepad.Note')

我认为这涉及到闭包编译器的目标和设计问题。正如@Technetium所指出的,使用闭包编译器“非常冗长”——它需要在JavaScript代码中添加注释,以说明每个方法(函数)的输入和输出类型以及对象(类)的每个属性的类型

(我不是编译器专家,但)我认为按照你的建议去做需要编译器“理解”你的代码,并猜测你认为什么是类,什么是构造函数、方法或该类的其他属性。这将是一个比闭包编译器设计人员所遇到的问题要困难得多的问题,特别是因为JavaScript是一种“松散”的语言,它允许你做任何你能想到的事情

实际上,我发现
goog.provide
一点也不麻烦。我通常只为每个文件定义一个类。我发现更麻烦的是所有的
google.require
语句。我经常可以在一个文件中有20或30个这样的文件,并且这个文件列表经常在类似的类中重复。我的代码中出现了3870次
goog.require

即使这样也没问题,但更糟糕的是闭包编译器有一个
goog.scope
机制,它允许您使用较短的名称,就像我可以说
Vector
而不是
新的myphysicslab.lab.util.Vector
。这很好,但问题是,您已经
goog.require
d的每个类都必须在
goog.scope
中创建一个短变量,行如下:

var Vector = myphysicslab.lab.util.Vector;
无论如何,我的观点是:是的,闭包编译器需要比原始JavaScript多得多的代码。但是,
goog.provide
是这方面的最小问题

还有一件事:user@Technetium states

使用它的真正原因是通过javascript-to-javascript闭包编译器运行Google闭包代码,该编译器可以删除死代码/未使用的代码,同时最小化和混淆您使用的代码片段

虽然这是一个非常有用的特性,但使用闭包编译器还有另一个非常重要的原因:类型检查。如果您花时间将注释添加到函数中,那么编译器将通过捕获错误来“支持您”。这对任何项目都是一个很大的帮助,但是当您有多个开发人员在一个项目上工作并且是t