我的新工作是使用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删除。
答案 0 :(得分:6)
假设您正在使用Closure Compiler,请考虑goog.scope
。有内置的编译器支持,可以在优化之前替换别名变量:
goog.scope
- 来自Closure Library wiki goog.scope
goog.scope
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支持的防止全局范围冲突的方法是在编译(source)之后引入一个立即调用的函数表达式。使用编译器标志:--output_wrapper "(function(){%output%})();"
或符合严格模式的变体:--output_wrapper "(function(){%output%}).call(this);"
。使用时,您老板不鼓励的快捷方式可以避免与外部符号发生冲突。
答案 1 :(得分:1)
如何使用立即函数创建单独的本地上下文:
(function () {
var SF = com.bin.slash.dot.closure.widget.SuperForm = function(){};
}());
您的代码只能放在此函数中。这样你就永远不会覆盖任何全局变量。
答案 2 :(得分:1)
定义引用以简化工作流程IMO没有任何问题。
var
widget = com.bin.slash.dot.closure.widget
widget.methA = function(){ widget.propertyA = 10}
命名空间有一个目的,虽然我不能在您的代码库上发言,但是有可能有更好的方法来组织这个库。