我的新工作是使用Google Closure库编写面向组件的JavaScript.我喜欢活动,组件,服务和模块.但由于需要编写混乱使用命名空间的代码,因此工作非常苛刻.以下代码是典型的:
goog.provide(com.bin.slash.dot.closure.widget.SuperForm); goog.require(com.bin.slash.dot.closure.widget.Avatar); // ... ten require calls more... com.bin.slash.dot.closure.widget.SuperForm = function() { goog.base(this); this._internal = new com.bin.slash.dot.closure.widget.Avatar( com.bin.slash.dot.closure.widget.Avatar.SRC_PATH); };
我无法相信这是真的.我并不害怕输入所有这些,但我只是觉得逻辑在这个符号地狱中消失了.扫描非常困难,因此需要更多时间来了解正在发生的事情.我的老板说,不鼓励写下以下快捷方式:
var SF = com.bin.slash.dot.closure.widget.SuperForm = function(){};
因为所有这些都将在编译后绑定到全局命名空间(窗口),因此它们可能会干扰其他内容.
问题是如何避免这个符号地狱?
更新:我改进了我的开发人员流程,解决了地狱的问题.现在我编写了甜蜜的JavaScript,然后由Grunt使用sweet.js宏自动编译:
// For each file I define three macros which are replaced // in the compile time with hell of a long paths. macro dir { rule { $x } => { my.very.very.long.namespace $x } } macro class { rule { $x } => { dir.NameOfMyClass $x } } macro proto { rule { $x } => { class.prototype $x } } dir.NameOfMyClass = function() {}; // yields: my.very.very.long.namespaceNameOfMyClass = function() {}; class.CONSTANT = "I don't know why we write constants into classes, not prototypes"; // yields: my.very.very.long.namespaceNameOfMyClass.CONSTANT = ...; proto.method1 = function() {}; // yields my.very.very.long.namespaceNameOfMyClass.prototype.method1 = function(){};
宏编译器创建的所有噪声都被优秀的shelljs删除.
假设您正在使用Closure Compiler,请考虑goog.scope
.有内置的编译器支持,可在优化之前替换别名变量:
Closure Library更简洁goog.scope
- 来自Closure Library wiki的设计文档
谷歌JavaScript风格指南:别名与 goog.scope
文档 goog.scope
Closure Library代码中的源代码示例
goog.provide
和goog.require
语法没有改变;
您可以在范围内开始声明非构造函数名称空间;
构造函数名称空间需要在重命名它们的作用域之外声明.
考虑到上述指南,您的代码示例可能看起来像这样:
goog.provide('my.very.long.namespace.NameOfMyClass'); goog.require('my.very.long.namespace'); /** @constructor */ my.very.long.namespace.NameOfMyClass = function() { /*...*/ }; goog.scope(function() { var _ = my.very.long.namespace.NameOfMyClass; _.CONSTANT = 'I don\'t know why we write constants into classes, not prototypes'; _.prototype.method1 = function() {}; }); // goog.scope
由于我没有足够的声誉来添加评论:
我的老板说,不鼓励写下以下快捷方式:
var SF = com.bin.slash.dot.closure.widget.SuperForm = function(){};因为所有这些都将在编译后绑定到全局命名空间(窗口),因此它们可能会干扰其他内容.
即使没有这些快捷方式,高级编译也可以重命名符号,例如SF
或 myVariable
简单ga
.这可能会导致与Google Analytics等外部代码发生冲突.
Closure支持的防止全局范围内此类冲突的方法是在编译后引入一个立即调用的函数表达式(源代码).使用编译器标志:--output_wrapper "(function(){%output%})();"
或符合严格模式的变体:--output_wrapper "(function(){%output%}).call(this);"
.使用时,老板不鼓励的快捷方式可以避免与外部符号发生冲突.