[英]Preventing inlining of exported properties as constants w/ Google Closure Compiler
Here's a minimal example of input JavaScript (generated by another language, but that's neither here nor there): 这是输入JavaScript的最小示例(由另一种语言生成,但这既不是这里也不是那里):
goog.provide('foo.bar');
foo.bar.baz = 42;
goog.exportSymbol('foo.bar.baz', foo.bar.baz);
foo.bar.quux = (function quux(){return foo.bar.baz;
});
goog.exportSymbol('foo.bar.quux', foo.bar.quux);
My expectation is that, because foo.bar.baz
is not annotated as a constant, that it would not be treated as one. 我的期望是,因为
foo.bar.baz
未被注释为常量,所以不会将其视为一个常量。 Yet, advanced optimizations (both locally and via the compiler service ) inlines it anyway: 但是,无论如何,高级优化(无论是在本地还是通过编译器服务 )都可以内联:
var d = this;
function f(g, e) {
var b = g.split("."), a = d;
b[0] in a || !a.execScript || a.execScript("var " + b[0]);
for (var c;b.length && (c = b.shift());) {
b.length || void 0 === e ? a = a[c] ? a[c] : a[c] = {} : a[c] = e;
}
}
;f("foo.bar.baz", 42);
f("foo.bar.quux", function() {
return 42;
});
Constant inlining is great, but the value in question isn't safe to inline, given that it's exported. 常量内联非常好,但是考虑到已导出的值,因此内联的值并不安全。 I've tried using
goog.exportProperty
and @expose
annotations in addition to and instead of goog.exportSymbol
, with no luck. 我已经尝试使用
goog.exportProperty
和@expose
注释来代替goog.exportSymbol
,并且没有运气。
Help? 救命? Thanks!
谢谢!
Update: @expose
is now deprecated. 更新:
@expose
现在已弃用。 Answer updated with new method. 答案已使用新方法更新。
As you noted, @const
has no impact on inlining. 如您所述,
@const
联没有影响。 @const
only means that the value doesn't change (is assigned/set only once). @const
仅表示该值不变(仅分配/设置一次)。
@nocollapse
was specifically created to prevent property collapsing. @nocollapse
是专门为防止属性崩溃而创建的。 Given: 鉴于:
goog.provide('foo.bar');
/** @nocollapse */
foo.bar.baz = 42;
alert(foo.bar.baz);
The purpose of @nocollapse
in this case is to prevent the compiler from collapsing the property to something like: 在这种情况下,
@nocollapse
的目的是防止编译器将属性折叠为类似以下内容:
var a = 42;
alert(a);
However the compiler still knows from flow analysis that foo.bar.baz
is assigned the integer 42
and never changed. 但是,编译器仍从流分析中得知
foo.bar.baz
被分配了整数42
并且从未更改。 Therefore it's going to just use the known values. 因此,它将仅使用已知值。
The only reliable way to prevent inlining is to export the property: 防止内联的唯一可靠方法是导出属性:
goog.provide('foo');
goog.provide('foo.bar');
foo.bar.baz = 42;
goog.exportProperty(foo.bar, 'baz', foo.bar.baz);
alert(foo.bar.baz);
There is a known (albeit small) need to stipulate to the compiler that renaming is safe, but inlining is not. 已知(尽管很小)需要向编译器规定重命名是安全的,但内联不是。 See https://code.google.com/p/closure-compiler/issues/detail?id=971
请参阅https://code.google.com/p/closure-compiler/issues/detail?id=971
If you are not using closure library, the export would look like this: 如果您不使用闭包库,则导出将如下所示:
var foo = {};
foo.bar = {};
/** @nocollapse */
foo.bar.baz = 42;
foo.bar['baz'] = foo.bar.baz;
alert(foo.bar.baz);
If your goal is to make sure foo.bar.baz
isn't inlined OR renamed, then you would need either quoted properties and @nocollapse
. 如果您的目标是确保不内联或重命名
foo.bar.baz
,那么您将需要带引号的属性和@nocollapse
。
goog.provide('foo');
goog.provide('foo.bar');
/** @nocollapse */
foo.bar.baz = 42;
goog.exportProperty(foo.bar, 'baz', foo.bar.baz);
alert(foo.bar.baz);
If you are providing this namespace to others for use, then the best case is a combination of @nocollapse
to prevent collapsing and allow external updating and goog.exportSymbol
. 如果您要将此命名空间提供给他人使用,那么最好的情况是
@nocollapse
的组合,以防止崩溃并允许外部更新和goog.exportSymbol
。
goog.provide('foo');
goog.provide('foo.bar');
/** @nocollapse */
foo.bar.baz = 42;
goog.exportSymbol('foo', foo);
goog.exportProperty(foo, 'bar', foo.bar);
goog.exportProperty(foo.bar, 'baz', foo.bar.baz);
alert(foo.bar.baz);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.