繁体   English   中英

使用Google Closure编译器防止将导出的属性内联为常量

[英]Preventing inlining of exported properties as constants w/ Google Closure Compiler

这是输入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);

我的期望是,因为foo.bar.baz未被注释为常量,所以不会将其视为一个常量。 但是,无论如何,高级优化(无论是在本地还是通过编译器服务 )都可以内联:

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;
});

常量内联非常好,但是考虑到已导出的值,因此内联的值并不安全。 我已经尝试使用goog.exportProperty@expose注释来代替goog.exportSymbol ,并且没有运气。

救命? 谢谢!

更新: @expose现在已弃用。 答案已使用新方法更新。

如您所述, @const联没有影响。 @const仅表示该值不变(仅分配/设置一次)。

@nocollapse是专门为防止属性崩溃而创建的。 鉴于:

goog.provide('foo.bar');
/** @nocollapse */
foo.bar.baz = 42;
alert(foo.bar.baz);

在这种情况下, @nocollapse的目的是防止编译器将属性折叠为类似以下内容:

var a = 42;
alert(a);

但是,编译器仍从流分析中得知foo.bar.baz被分配了整数42并且从未更改。 因此,它将仅使用已知值。

防止内联的唯一可靠方法是导出属性:

goog.provide('foo');
goog.provide('foo.bar');
foo.bar.baz = 42;
goog.exportProperty(foo.bar, 'baz', foo.bar.baz);
alert(foo.bar.baz);

已知(尽管很小)需要向编译器规定重命名是安全的,但内联不是。 请参阅https://code.google.com/p/closure-compiler/issues/detail?id=971

如果您不使用闭包库,则导出将如下所示:

var foo = {};
foo.bar = {};
/** @nocollapse */
foo.bar.baz = 42;
foo.bar['baz'] = foo.bar.baz;
alert(foo.bar.baz);

如果您的目标是确保不内联或重命名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);

如果您要将此命名空间提供给他人使用,那么最好的情况是@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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM