为什么 CoffeeScript 编译成单一的 JavaScript?
Why does CoffeeScript compile to unidiomatic JavaScript?
我正在尝试使用 Coffee 脚本(我是新手 "language")并尝试了一个非常基本的示例:
x = [1, 2, 3]
for element in x
console.log(element)
这就是它所说的,对于它输出到控制台的每个元素。只有当我在 Javascript 它编译成的时候花了很多时间,我才不明白他们为什么这样做:
(function() {
var element, i, len, x;
x = [1, 2, 3];
for (i = 0, len = x.length; i < len; i++) {
element = x[i];
console.log(x[i]);
}
}).call(this);
这样做会不会更好更自然:
for(i = 0; i < x.length; i++)
{
console.log(x[i]);
}
为什么 coffee 脚本编译成这样看起来不自然的方式?如果我在 Javascript 中编写完全相同的代码,我会遵循我所做的方法,但我可能错了,因为我这样做的方式 (Javascript) 不是最有效的或 "natural" 而coffee script方法是更好的解决方案。
基本上,您期望 CoffeeScript 编译器执行非常复杂的杂技操作。
考虑这个 CoffeeScript:
for a in x
console.log(a)
for b in a
console.log(b)
callFunc(b)
这会转换为:
for (i = 0, len = x.length; i < len; i++) {
a = x[i];
console.log(a);
for (j = 0, len1 = a.length; j < len1; j++) {
b = a[j];
console.log(b);
callFunc(b);
}
}
很容易看出原始 CoffeeScript 如何对应于结果 JavaScript:
for [variable] in [array]
[body]
变成
for (var [letter] = 0, len = [array].length, [letter] < len; [letter]++) {
[variable] = [array][[letter]]
[body converted to JavaScript]
}
所以当把一个for
理解翻译成JavaScript时,(几乎)所有编译器需要担心的就是这个简单的对应关系,然后它可以向内工作并将主体作为一个单独的部分处理并独立运作。
此外,len = [array].length
缓存是为了提高性能。这看起来并不令人愉快,而且大多数人不会以这种方式编写代码,但是生成漂亮的 JavaScript 并不是 CoffeeScript 的主要目标。它生成高效代码的前提是人们通常不会阅读生成的 JavaScript.
您的建议是将原始代码转换为:
for (i = 0; i < x.length; i++) {
console.log(x[i]);
for (j = 0; j < x[i].length; j++) {
console.log(x[i][j]);
callFunc(x[i][j]);
}
}
为了将 console.log(b)
转换为 console.log(b);
,编译器不需要知道 任何 围绕该语句的代码。为了将 console.log(b)
转换为 console.log(x[i][j]);
,编译器必须考虑该语句周围的 一切 。它会给编译器带来极其复杂的工作,并且不会真正提供任何好处。
首先,CoffeeScript 默认在闭包中构建所有内容,即这些行:
(function() {
}).call(this);
闭包防止变量从脚本中泄漏出来。如果您想将脚本导出为全局脚本,则需要将其显式附加到全局,例如 window
.
下一行是:
var element, i, len, x;
在使用之前声明您的 var
被认为是好的做法(至少根据 jslint)。
你对x的定义当然是:
x = [1, 2, 3];
现在循环:
for (i = 0, len = x.length; i < len; i++) {
element = x[i];
console.log(x[i]);
}
首先定义 len
可以防止循环不断地查找 x.length
是什么。只有三个项目的速度差异不大,但是一个 10k 的数组,嗯...
console.log
很明显,但 element
变量已定义,因为这是您在编写循环时指定的变量名称。它使用 i
而不是元素进行迭代,主要是因为使用 i
进行迭代是标准做法。
所以你看到一切都有合理的理由,尽管对某些人来说有点冗长。
我正在尝试使用 Coffee 脚本(我是新手 "language")并尝试了一个非常基本的示例:
x = [1, 2, 3]
for element in x
console.log(element)
这就是它所说的,对于它输出到控制台的每个元素。只有当我在 Javascript 它编译成的时候花了很多时间,我才不明白他们为什么这样做:
(function() {
var element, i, len, x;
x = [1, 2, 3];
for (i = 0, len = x.length; i < len; i++) {
element = x[i];
console.log(x[i]);
}
}).call(this);
这样做会不会更好更自然:
for(i = 0; i < x.length; i++)
{
console.log(x[i]);
}
为什么 coffee 脚本编译成这样看起来不自然的方式?如果我在 Javascript 中编写完全相同的代码,我会遵循我所做的方法,但我可能错了,因为我这样做的方式 (Javascript) 不是最有效的或 "natural" 而coffee script方法是更好的解决方案。
基本上,您期望 CoffeeScript 编译器执行非常复杂的杂技操作。
考虑这个 CoffeeScript:
for a in x
console.log(a)
for b in a
console.log(b)
callFunc(b)
这会转换为:
for (i = 0, len = x.length; i < len; i++) {
a = x[i];
console.log(a);
for (j = 0, len1 = a.length; j < len1; j++) {
b = a[j];
console.log(b);
callFunc(b);
}
}
很容易看出原始 CoffeeScript 如何对应于结果 JavaScript:
for [variable] in [array]
[body]
变成
for (var [letter] = 0, len = [array].length, [letter] < len; [letter]++) {
[variable] = [array][[letter]]
[body converted to JavaScript]
}
所以当把一个for
理解翻译成JavaScript时,(几乎)所有编译器需要担心的就是这个简单的对应关系,然后它可以向内工作并将主体作为一个单独的部分处理并独立运作。
此外,len = [array].length
缓存是为了提高性能。这看起来并不令人愉快,而且大多数人不会以这种方式编写代码,但是生成漂亮的 JavaScript 并不是 CoffeeScript 的主要目标。它生成高效代码的前提是人们通常不会阅读生成的 JavaScript.
您的建议是将原始代码转换为:
for (i = 0; i < x.length; i++) {
console.log(x[i]);
for (j = 0; j < x[i].length; j++) {
console.log(x[i][j]);
callFunc(x[i][j]);
}
}
为了将 console.log(b)
转换为 console.log(b);
,编译器不需要知道 任何 围绕该语句的代码。为了将 console.log(b)
转换为 console.log(x[i][j]);
,编译器必须考虑该语句周围的 一切 。它会给编译器带来极其复杂的工作,并且不会真正提供任何好处。
首先,CoffeeScript 默认在闭包中构建所有内容,即这些行:
(function() {
}).call(this);
闭包防止变量从脚本中泄漏出来。如果您想将脚本导出为全局脚本,则需要将其显式附加到全局,例如 window
.
下一行是:
var element, i, len, x;
在使用之前声明您的 var
被认为是好的做法(至少根据 jslint)。
你对x的定义当然是:
x = [1, 2, 3];
现在循环:
for (i = 0, len = x.length; i < len; i++) {
element = x[i];
console.log(x[i]);
}
首先定义 len
可以防止循环不断地查找 x.length
是什么。只有三个项目的速度差异不大,但是一个 10k 的数组,嗯...
console.log
很明显,但 element
变量已定义,因为这是您在编写循环时指定的变量名称。它使用 i
而不是元素进行迭代,主要是因为使用 i
进行迭代是标准做法。
所以你看到一切都有合理的理由,尽管对某些人来说有点冗长。