- PVSM.RU - https://www.pvsm.ru -

Ещё один препроцессор для JavaScript

Интересна ли вам возможность писать в JavaScript вот такие штуки?

$ ('.btn-toogle').onclick (lambda $ (this).toggleClass ('active'));

var chars = Array.prototype.forEach.call ('0123456789abcdef', lambda arg.charCodeAt (0));

function fn (arg1 = 100, arg2 = 'test'){ ... }

var html = h`
    <div>
        <a href="...">link</a>
    </div>`;

for (var key, value in object) 
    console.log (key + ' = ' + value);

Тогда, возможно, вас заинтересует эта статья.

Не буду расписывать всякую скукоту вроде истории или того, зачем я сделал эту штуку. Лучше попробую вкратце рассказать, как она работает и что она может делать.

Препроцессор написан на Node.JS, причём для парсинга JavaScript'а используется генератор парсеров PEG.js [1]. Кстати, одной из сильных сторон препроцессора (ну, лично для меня) является то, что обычный JavaScript-код отлично парсится. Ну, если, конечно же, в коде не встречаются ключевые слова вроде lambda, module, import или export.

Конечно, парсер на JavaScript не отличается производительностью, но, к счастью, кеширование вполне это компенсирует.

Большинство фич уже описано выше, но сейчас я попробую рассказать о них поподробнее.

1. Сокращённая запись функций.

var way0   = lambda arg.charCodeAt (0),
    way1   = lambda (arg) arg.charCodeAt (0),
    way2   = lambda { return arg.charCodeAt (0) },
    way3   = lambda (arg){ arg.charCodeAt (0) },
    result = function (arg){ return arg.charCodeAt (0) };

Все четыре способа записи дают одинаковый результат. Аргумент «arg» добавляется тем функциям, у которых отсутствуют обычные аргументы. Если всё тело функции состоит из одной операции (statement; если честно, не знаю, как корректно сказать по-русски), функция вернёт результат этой операции.

Вот ещё пара примеров:

var // Вернёт сумму четырёх аргументов
	example0 = lambda (a, b, c, d) a + b + c + d,   

	// Некий аналог forEach
    example1 = lambda (a, fn) 
    	for (var i = 0; i < a.length; i ++)
    		fn (a [i]),	

    // Вернёт объект с полями a и b.							
    example2 = lambda { 
    	a: arg * 2, 
    	b: arg
    };

2. Аргументы функций по умолчанию.

Ничего особенно, заголовок уже говорит сам за себя.

function fn (arg1 = 100, arg2 = 'test'){ ... }

Аргументы будут сравниваться (без приведения типов) с undefined. Если вдруг они окажутся равны, им будут выставлены значения по умолчанию.

3. Многострочные строки (прошу прощения за столь некрасивое выражение).

Для начала, это просто способ записи строк с использованием символа «`» как кавычек. Можно наконец-то перестать расставлять «» в концах строк (хотя, признаюсь, никто обычно не пишет так, чтобы были нужны многострочные строки). Но это ещё не всё. В записимости от символа перед открывающей кавычкой препроцессор может как-то по-особенному обработать текст внутри. Напишите «h» и препроцессор сожмёт строку как html-код, «c» — как css-код, «s» — удалит идущие подряд пробелы, «l» — сконвертирует LESS внутри строки в CSS (ну и сожмёт тоже), а «lp» — мой любимый :) — не только сконвертирует LESS в CSS, но и оставит возможность в дальнейшем определять свойства через JavaScript. Довольно удобно.

4. Модули.

Если коротко, это в каком-то смысле аналог классов из той же Java. Но ни в коем случае не обычных классов. В JavaScript же уже есть прототипы, верно?

Модули заменяют собой то, что в других языках обычно называется статическими классами (надеюсь, такой термин вообще существует).

Пример простого модуля:

module Example {
    function init (){
        // ...
    }
}

Функция «init» будет вызвана при запуске скрипта (ну, об этом попозже).

А так выглядят два модуля, если один из них используется другим:

module First {
    export function test (){
        console.log ('Эта строчка будет выведена третьей.');
    }

    function init (){
        console.log ('Эта — первой.');
    }
}

module Second {
    import First;

    function init (){
        console.log ('Ну а эта — второй, так как вначале будут проинициализированы все модули, включённые в этот.');
        First.test ();
    }
}

Если поставить перед именем импортируемого класса «@», импортируемый класс может быть проинициализирован и позже импортирующего. Помогает, если каждому из двух классов вдруг понадобится импортировать другой, хотя, конечно же, архитектурно такая структура выглядит отталкивающе.

Ну а ещё есть доступные лишь на чтение экспортируемые переменные:

module First {
    import @Second;

    export function test (){
        console.log ('Тут сейчас будет написано «1024»: ' + Second.value);
    }
}

module Second {
    import First;

    export var value = 1024;

    function init (){
        First.test ();
    }
}

Кстати, модули необязательно использовать именно другими модулями. Хотя и желательно. :)

5. Параметры препроцессора.

Чтобы настроить сборку кода, можно использовать хитрые комментарии в начале файла:

// ==Jsx==
// @target     web:onload
// @build-to   build/
// @define     __VERSION__ 1.00
// @import     utils/string.format
// @include     jquery.min.js
// ==/Jsx==

(Примерно в таком же стиле записываются комментарии для UserScript'ов.)

  • target — указывает, где будет выполняться скрипт. От этого аргумента зависит код, инициализирующий модули. Допустимые значения: «web» (будет использоваться переменная window), «web:onload» (модули начнут инициализироваться после завершения загрузки страницы), «node» (для Node.JS, будет использоваться GLOBAL), «local».
  • build-to — указывает, куда сохранить результат. По умолчанию скрипт сохраняет его в ту же папку, заменив расширение «jsx» на «js» (или добавив расширение «js», если у оригинального файла расширение отличается от «jsx».
  • define — заменит в результирующем файле все вхождения первого аргумента на второй. Иногда пригождается.
  • import — включит файл с расширением «jsxi» (которое писать в параметре не нужно), предварительно распарсив. Если файл не будет найден в папке рядом, поиск продолжится в папке с подключаемыми файлами препроцессора. (Ну, там довольно хитрый алгоритм; пожалуй, не стоит тут расписывать такие мелочи.)
  • include — включит файл в результат, никак не анализируя и не парся.

Это не все параметры, а так же не все фичи, но, по-моему, статья и так получилась чересчур великовата для краткого описания.

Скачать текущую версию можно отсюда [2]. Заранее прошу прощения за все возможные ошибки и благодарю за уделённое внимание. :)

Автор: x4fab

Источник [3]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/42374

Ссылки в тексте:

[1] PEG.js: http://pegjs.majda.cz/

[2] отсюда: https://github.com/gro-ove/js-ext

[3] Источник: http://habrahabr.ru/post/191858/