2015-02-26 2 views
0

Я играл с кофе сценарий (я новичок в этом «языке») и попытался лишь очень простой пример:Почему CoffeeScript компилируется в унииоматический JavaScript?

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

Почему кофейный скрипт компилируется таким образом, который не кажется естественным? Если бы я писал тот же самый точный код в Javascript, я бы выполнил метод, который я сделал, но я мог ошибаться в том, что так, как я это сделал (Javascript), не самый эффективный или «естественный», а метод сценария кофе лучшие решения.

+1

'len = x.length' означает, что они кэшируют значение' x.length' в 'len', а не вычисляют длину x при каждом проходе через цикл. это может показаться не «естественным» способом, а его оптимальным способом, который вы хотите получить от компилятора/препроцессора. они создают clsure/sef, чтобы избежать глобальных привязок. (если у вас больше кода в примере, это имеет смысл) – atmd

+0

Проверьте этот инструмент: http://js2.coffee/ Очень полезно при сравнении JS с CoffeeScript. – kuba

+1

@atmd - ударить ноготь по голове - ключевое слово здесь ** оптимальное **. Преобразованный код должен быть оптимальным и не обязательно «естественным» способом, которым разработчик мог бы написать код. – Lix

ответ

4

В основном вы ожидаете, что компилятор CoffeeScript сделает акробатику, которая будет очень сложной.

Рассмотрим CoffeeScript:

for a in x 
    console.log(a) 
    for b in a 
    console.log(b) 
    callFunc(b) 

Это transpiles к:

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] 
} 

Итак, при переходе в 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]);, компилятор должен был бы принять все вокруг этого утверждения во внимание. Это дало бы компилятору чрезвычайно сложную работу для выполнения и не принесло бы никакой пользы.

+1

+1. Coffeescript - простой транспилятор, а не оптимизирующий компилятор с тяжелым статическим анализом и «акробатикой». – Bergi

+0

BTW, [этот аргумент о «производительности» вполне может быть полным BS] (http://mrale.ph/blog/2014/12/24/array-length-caching.html). –

1

Во-первых, CoffeeScript строит все в закрытии по умолчанию, что бы эти строки:

(function() { 
    }).call(this); 

Затворы предотвратить переменные течи из сценария. Если вы хотите экспортировать скрипт как глобальный, то вам нужно явно привязать его к глобальному, например window.

Далее идет строка:

var element, i, len, x; 

Это считается хорошей практикой объявлять var перед тем, чтобы использовать их (по крайней мере, по jslint).

Ваше определение х конечно:

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.

Итак, вы видите, что все имеет законную причину, хотя и немного подробный для некоторых вкусов.

+0

«но массив с 10k, ну ...» - там [это может быть действительно хуже] (http://mrale.ph/blog/2014/12/24/array-length-caching.html), чтобы сделать это ручная «оптимизация» ... –

Смежные вопросы