如果我给Closure Compiler这样的东西:

window.array = '0123456789'.split('');

它“编译”为:
window.array="0,1,2,3,4,5,6,7,8,9".split(",");

现在,您可以说,更大。 Closure Compiler为什么要这样做?

最佳答案

我认为这是正在发生的事情,但我不确定...

引起逗号插入的代码是PeepholeSubstituteAlternateSyntax.java中的tryMinimizeStringArrayLiteral

该方法包含一个字符列表,这些字符可能具有较低的Huffman encoding,因此比其他字符更可拆分。如果尝试以下操作,则可以看到此结果:

"a b c d e f g".split(" "); //Uncompiled, split on spaces
"a,b,c,d,e,f,g".split(","); //Compiled, split on commas (same size)

编译器将使用您认为适合的字符替换您尝试分割的字符。它通过遍历字符串的字符并找到字符串中没有出现的最有利的拆分字符来实现:
// These delimiters are chars that appears a lot in the program therefore
// probably have a small Huffman encoding.
NEXT_DELIMITER: for (char delimiter : new char[]{',', ' ', ';', '{', '}'}) {
  for (String cur : strings) {
    if (cur.indexOf(delimiter) != -1) {
      continue NEXT_DELIMITER;
    }
  }
  String template = Joiner.on(delimiter).join(strings);
  //...
}

在上面的代码片段中,您可以看到编译器声称可以拆分的最佳字符数组。首先使用逗号(这就是为什么在上面的空格示例中,空格已被逗号替换)。

我相信在要分割的字符串为空字符串的情况下插入逗号可能只是疏忽。在这种情况下,似乎没有任何特殊处理,因此将其与任何其他split调用一样对待,并且每个字符都与上述片段中显示的数组中的第一个适当字符相连接。

编译器如何处理split方法的另一个示例:
"a,;b;c;d;e;f;g".split(";"); //Uncompiled, split on semi-colons
"a, b c d e f g".split(" "); //Compiled, split on spaces

这次,由于原始字符串已经包含逗号(并且我们不想在逗号字符上分割),因此不能从低霍夫曼编码的字符数组中选择逗号,因此下一个最佳选择是选择(空格)。

更新

经过对此的进一步研究,它绝对不是错误。这种行为实际上是设计使然,我认为这是一个非常聪明的小优化,当您记住Closure编译器倾向于偏爱编译代码的速度而不是大小时。

上面我提到了霍夫曼编码两次。霍夫曼编码算法的解释非常简单,它为出现在待编码文本上的每个字符分配了权重。权重取决于每个字符出现的频率。这些频率用于构建二叉树,最常见的字符位于根。这意味着最常见的字符更容易解码,因为它们更接近树的根。

而且由于霍夫曼算法是gzip使用的DEFLATE算法的很大一部分。因此,如果将Web服务器配置为使用gzip,您的用户将受益于这种巧妙的优化。

关于javascript - 为什么Closure Compiler坚持添加更多字节?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10210421/

10-12 14:05