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