Статьи

Функциональный JavaScript с Underscore.js

JavaScript — очень универсальный язык, так как он может использоваться для процедурного, объектно-ориентированного или даже функционального программирования.

Например, вы можете легко определить анонимные функции в JavaScript в любой точке выполнения:

var f = function() { ... };

Эти функции могут передаваться как переменные, удовлетворяющие одной из предпосылок функционального программирования:

doSomething(f, ...);

Анонимные функции становятся замыканиями, автоматически связываясь с существующими переменными каждый раз, когда вы цитируете их в реализации:

var selector = '#someId';
var html = function(content) { $(selector).html(content); };

Расширяя шаблон, также очень легко определить функции, которые возвращают другие функции:

var write = function(selector) {
    var html = function(content) { $(selector).html(content); };
};

реализовать какую-то конкретную версию карри.

Underscore.js

Есть несколько проблем с функциональным JavaScript, которые Underscore.js пытается решить как внешнюю библиотеку.

Первая проблема заключается в том, что многие примитивы, представленные функциональными языками , такими как map, filter и Reduce, отсутствуют в спецификациях ECMAScript.

Более того, хотя было бы неплохо представить их в единую библиотеку, мы не хотим вторгаться в глобальное пространство имен или даже в базовые объекты, такие как Array , изменяя их прототипы, добавляя удобные функции, такие как Array.map (). В случае, если мы нацелены на функциональный подход, нам даже не нужно присоединять функции к прототипам, поскольку они могут оставаться отдельным пространством имен.

Underscore.js является автономным и не имеет внешних зависимостей; он предоставляет каждую встроенную функцию как часть глобального объекта _ (например, _.map ()). Отсюда следует, что конфликт с другими библиотеками и существующими структурами данных, на которые опирается ваш код, минимален, однако накладные расходы на вызов этих функций составляют несколько символов написания _.

Примеры

Вот отдельная HTML-страница, которая использует Underscore.js для выполнения некоторых простых вычислений с целью показать вам реализацию некоторых популярных функциональных примитивов, таких как map и lower.

Эта страница также зависит от jQuery для удобного отображения результатов, но Underscore.js можно использовать отдельно или в сочетании с другими платформами. Обратите внимание, что на этой странице я удаленно загружаю исходные файлы JavaScript в их версии для разработки, чтобы упростить пример.

<html>
<head>
<script src="http://code.jquery.com/jquery-1.7.2.js"></script>
<script src="http://underscorejs.org/underscore.js"></script>
<script type="text/javascript">
    $(function() {
        var primeNumbers = [2, 3, 5, 7, 11];
        var listIn = function(selector) {
            return function(num){
                $(selector).append('<p>' + num + '</p>');
            };
        }
        _.each(primeNumbers, listIn('#primenumbers'));

        var square = function(num) { return num * num; };
        _.each(_.map(primeNumbers, square), listIn('#theirsquares'));

        var sum = function(a, b) { return a + b; };
        var listInSum = listIn('#sum');
        listInSum(_.reduce(primeNumbers, sum, 0));

        var even = function(num) { return num % 2 == 0; };
        _.each(_.filter(primeNumbers, even), listIn('#even'));

        var odd = function(num) { return !even(num); };
        listIn('#allodd')(_.all(primeNumbers, odd));
    });
</script>
</head>
<body>
    <div id="primenumbers">Prime numbers</div>
    <div id="theirsquares">Their squares</div>
    <div id="sum">Their sum</div>
    <div id="even">The even ones</div>
    <div id="allodd">Are all primes odd?</div>
</body>
</html>

каждый из них является примитивом, вызывающим функцию для каждого элемента коллекции (большинство этих примитивов работают как с массивами, так и с объектами).

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

Другой очень известная функциональная операция является самоописываемым фильтром , но есть очень много примитивов , включенных в Underscore.js, как все , любой , отвергает , и найти . В случае массивов, которые эквивалентны спискам в JavaScript, есть также классические first , rest , zip и так далее.

Еще…

Существует много синтаксических помех в кодировании в функциональном стиле в JavaScript: это язык, который мало разделяет с семейством LISP. Например, отсутствует поддержка автоматического каррирования или отложенной оценки структур данных. JavaScripts не полагается на ссылочную прозрачность, как настоящие функциональные языки, такие как Clojure.

Другая проблема заключается в эффективности, так как это происходит каждый раз, когда вы включаете внешнюю библиотеку для базовых операций, таких как манипулирование массивами. Для решения этой проблемы Underscore.js делегирует собственные функции там, где они доступны: в этом случае основные операции, подобные каждой, будут скомпилированы в самом браузере. В любом случае вам не нужно проверять, поддерживает ли браузер ту функцию, которую вы хотите.

Ресурсы

Чтобы узнать больше о функциональных концепциях и их применении к JavaScript, см. Эту классическую статью на IBM developerWorks .

JavaScript более высокого порядка поможет вам в реализации функциональных примитивов и включает расширенные примеры кода.

Если вы хотите начать использовать Underscore.js, прочитайте аннотированный исходный код в качестве основной формы документации (которая в любом случае генерируется из этого). Иногда стоит заглянуть в примитива, которого вы не знаете, как позвонить, чтобы действительно увидеть, что происходит.