我有以下代码:
var NS = {}; // namespace
NS.myEnum = {
foo: 1,
bar: 2
};
var extendedNS = Object.create(NS);
extendedNS.myAlert = function (x) { alert(x); };
extendedNS.myAlert(extendedNS.myEnum.foo);
使用此命令成功编译(没有警告或错误):
java -jar compiler-20150609.jar --js test.js --compilation_level ADVANCED --warning_level VERBOSE
根据docs for JSC_UNSAFE_NAMESPACE
,我认为高级优化可能会将NS.myEnum
替换为NS$myEnum
,然后移除NS
。
那么为什么编译器不会对此行发出警告?
var extendedNS = Object.create(NS);
这不是对名称空间NS
的不安全引用吗?不应该编译器警告:"为命名空间NS
" 创建了不完整的别名?
我现在将NS.myEnum
标记为枚举:
/**
* @enum {number}
*/
NS.myEnum = {
foo: 1,
bar: 2
};
根据this old SO answer,"编译器希望将枚举值折叠为单个变量" 。所以我认为编译器现在可以将NS.myEnum
折叠为:
NS$myEnum$foo = 1;
NS$myEnum$bar = 2;
编译器现在发出警告:
WARNING - incomplete alias created for namespace NS
var extendedNS = Object.create(NS);
^
我想我理解为什么:在折叠枚举值后,高级优化可能已删除NS
。
编译后的输出确实已损坏:
var a = Object.create({});
a.a = function() {
alert(a.c.b); // a.c.b doesn't exist, so a runtime error will occur
};
a.a();
我现在向枚举添加@nocollapse
标记("表示编译器不应将其折叠为变量的属性。如果使用{注释属性为对象的属性{1}},其所有属性也将保持未折叠状态。" ):
@nocollapse
编译后的输出现在是有效代码:
/**
* @enum {number}
* @nocollapse
*/
NS.myEnum = {
foo: 1,
bar: 2
};
但是编译器仍然会发出var a = Object.create({c:{a:1, f:2}});
a.b = function() {
alert(a.c.a); // a.c.a does exist
};
a.b();
警告:
JSC_UNSAFE_NAMESPACE
为什么呢?我需要在WARNING - incomplete alias created for namespace NS
var extended = Object.create(NS);
^
添加另一个标记来阻止此警告吗?
(注意:我不想NS.myEnum
警告。我想了解并解决警告的原因。)
答案 0 :(得分:1)
核心问题归结为传统上@enum
属性一直被折叠 - 因此当@enum
注释被添加为代码时警告会被破坏(并且在您的第一个示例中) )。
@nocollapse
会阻止枚举折叠,并且当存在该注释时,可能会错误地发出警告。如果您愿意,可以file a bug关于此问题,但这可能是一个低优先级问题。
在一般情况下,enums被设计为更像常量,因此使用它们作为proto对象不是预期/支持的行为。
围绕财产崩溃的规则和案例很复杂。了解它们的最佳方法是查看unit tests以查看触发警告的特定模式。