如果我给Closure Compiler这样的东西:
window.array = '0123456789'.split('');
它将其“编译”为以下内容:
window.array="0,1,2,3,4,5,6,7,8,9".split(",");
现在你可以看出来,它更大了。闭包编译器为什么会这样做呢?
如果我给Closure Compiler这样的东西:
window.array = '0123456789'.split('');
它将其“编译”为以下内容:
window.array="0,1,2,3,4,5,6,7,8,9".split(",");
现在你可以看出来,它更大了。闭包编译器为什么会这样做呢?
我认为这就是发生的事情,但我绝不确定...
导致插入逗号的代码位于PeepholeSubstituteAlternateSyntax.java中的tryMinimizeStringArrayLiteral
方法。
该方法包含一个字符列表,这些字符可能具有较低的哈夫曼编码,因此与其他字符相比,它们更适合拆分。如果您尝试类似于下面的内容,则可以看到其结果:
"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
由于原始字符串已经包含了逗号(我们不想在逗号字符上进行拆分),因此逗号不能从低Huffman编码字符数组中选择,所以选择了次优选择(空格)。
更新
经过进一步的研究,这绝对不是一个错误。实际上,这种行为是有意设计的,而且在我看来,这是一个非常聪明的小优化,考虑到Closure编译器倾向于编译代码的速度而不是大小。
上面我提到了霍夫曼编码几次。霍夫曼编码算法简单地解释就是给文本中出现的每个字符分配一个权值。该权值基于每个字符出现的频率。这些频率用于构建二叉树,且最常见的字符位于根部。这意味着最常见的字符更容易解码,因为它们靠近树的根部。
由于Huffman算法是gzip使用的DEFLATE算法的重要组成部分。因此,如果您的Web服务器配置为使用gzip,则您的用户将从这个巧妙的优化中受益。
split
转换为直接赋值可以使代码更短,那么闭包编译器会进行转换。 - James Allardice.split("")
失败或以意外方式工作的情况?我认为没有这样的情况(我在许多浏览器中进行了测试,没有发现任何问题),因此值得提交错误报告。它似乎是一个相当大的疏忽,所以我很惊讶它以前没有出现过,这让我觉得可能是有意设计的。 - James Allardice具有讽刺意味的是,编译后的代码中的split
与源代码中的split
没有任何关系。请考虑以下内容:
Source : a = ["0","1","2","3","4","5"]
Compiled: a="0,1,2,3,4,5".split(",")
split
只是一种表示长数组的方法(足够长,使得所有引号和逗号的总和比split(","")
还要长)。那么,在你的例子中发生了什么?首先,编译器看到一个应用于常量的字符串函数,并立即评估它:'0123456789'.split('') => ["0","1","2","3","4","5","6","7","8","9"]
在稍后的某个时刻,当生成输出时,编译器会将这个数组视为“长”的,并按照上述的“分割”形式进行编写:
["0","1","2","3","4","5","6","7","8","9"] => "0,1,2,3,4,5,6,7,8,9".split(",")
split('')
的所有信息都已丢失。Source : a = '0123'.split('')
Compiled: a=["0","1","2","3"]
['0', '1', '2', '3', '4', '5', '6', '7']
不应该总是编译为'01234567'.split('')
吗? - qwertymksplit
调用,它就会编译任何直接字符串数组赋值。查看我回答中提到的方法的实现,以了解确切的情况。 - James Allardice