Javascript 为什么闭包编译器不缩短这个时间?

Javascript 为什么闭包编译器不缩短这个时间?,javascript,minify,google-closure-compiler,Javascript,Minify,Google Closure Compiler,我不确定这是一个bug还是一个预期的特性 基本上,我有一个很小的函数(我现在看到end在这里是蓝色的,但它工作得很好,如果我将它重命名为其他名称,我仍然有这个问题): 当我编译它时,我得到: function f(a,b){var c=Math.max(a,b);tb.selectionStart=Math.min(a,b);tb.selectionEnd=c}; 但是,为什么将selectionStart直接设置为Math.min,而将selectitonend设置为首先声明的变量(c)?做

我不确定这是一个bug还是一个预期的特性

基本上,我有一个很小的函数(我现在看到
end
在这里是蓝色的,但它工作得很好,如果我将它重命名为其他名称,我仍然有这个问题):

当我编译它时,我得到:

function f(a,b){var c=Math.max(a,b);tb.selectionStart=Math.min(a,b);tb.selectionEnd=c};
但是,为什么将
selectionStart
直接设置为
Math.min
,而将
selectitonend
设置为首先声明的变量(
c
)?做
tb.selectionEnd=Math.max(a,b)
不是更短吗


任何想法都将受到欢迎。

如果您粘贴此代码,这将起作用

function f(a, b) {
    var start = Math.min(a, b);
    tb.selectionStart = start;

    var end = Math.max(a, b);
    tb.selectionEnd = end;
};
函数f(a,b){tb.selectionStart=Math.min(a,b);tb.selectionEnd=Math.max(a,b)}

这是闭包编译器的错误。

编辑:此链接中有一个“官方”答案:

我认为对变量的赋值,然后立即使用该变量,可以内联。但是,如果中间有任何语句不能被证明没有副作用,那么编译器将不会内联它

在您的情况下,变量“start”的赋值与“start”的用法仅通过“end”的赋值语句分开。但是,该语句没有副作用,因为Math.max是一个内部函数,编译器知道它没有副作用

但是,在您的情况下,变量“end”的赋值与该变量的使用之间通过一条语句分隔开,该语句是对属性的“start”赋值。现在,我相信编译器并没有假设仅仅对属性赋值总是没有副作用的;这是因为某些属性在指定时实际上会导致不同的行为,或更改全局状态(例如RegExp)。在某些系统中,属性分配实际上会触发某些特定于系统的功能(例如硬件接口),而这些功能又可能包含副作用

这就是为什么有时,当您有这样的代码时:

foo.bar = 1;
foo.bar = 2;
foo.bar = 3;
编译器不会删除前两条语句,因为赋值给“bar”可能会有副作用

因此,在您的问题中,变量“end”不能内联,因为语句
tb.selectionStart=start可能有副作用(可能仅在wierd情况下)


如果您将“tb”设为局部变量,或编译器完全控制的对象(例如,一个简单对象:
var tb={};
),那么您会发现编译器将所有赋值都很好地内联起来。

我可以复制它,而我或您的顺序应该不会有任何区别。好吧,我想没有什么可以反对的。我把这个主题提交给了闭包编译器项目页面。希望这能解决。非常感谢。你这么做太好了。我认为这是一个副作用的问题——看看我的答案。我明白了,但是编译器不可能以这样的方式进行优化:
Math.max
被视为没有副作用吗?Math.max是一个JS内部函数,没有副作用。这在编译器的externs文件中。但是,您分配给tb.selectionStart的任务不能保证没有副作用。只有在赋值和用法之间没有可能包含副作用的语句时,才能内联var赋值。哦,我现在明白了。你可以通过以下实验来证明这一点:1)删除包装函数,2)删除“开始”和“结束”前面的“var”(从而使它们成为全局变量),3)编译。你会发现的,惊喜!,编译器既不删除“开始”也不删除“结束”。这是因为所有函数都可以访问全局变量,只要存在可能包含副作用的内容,它就可以访问这些全局变量!所以编译器必须让它们单独运行。想想“tb.selectionStart”打开一些硬件系统功能——JS不限于在浏览器中运行,你知道——它访问“start”和“end”变量。你明白了,这是副作用。当然,这是一种非常糟糕的程序编写方式,但编译器必须保守,并假设我们都编写危险的代码是为了自杀。顺便说一句,语法高亮显示是一种包罗万象的东西。它将尽最大努力突出任何语言。所以它并没有精确地检测JS,只是一个C语法,并给常用关键字加上颜色。此外,您还可以输出一个漂亮的打印版本的代码,这样可以更容易地了解闭包编译器的功能。
foo.bar = 1;
foo.bar = 2;
foo.bar = 3;