Как устроено функциональное приложение JavaScript на основе программирования?

StackOverflow https://stackoverflow.com/questions/2677532

Вопрос

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

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

var external;
function foo() {
   external = 'bar';
}
foo();

это создаст побочный эффект, верно?Итак, как правило, вы хотите избежать нарушения переменных в глобальной области видимости.

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

var Foo = function(initVars) {
   this.init(initVars);
}

Foo.prototype.init = function(initVars) {
   this.bar1 = initVars['bar1'];
   this.bar2 = initVars['bar2'];
   //....
}

var myFoo = new Foo({'bar1': '1', 'bar2': '2'});

Итак, мой метод init намеренно вызывает побочные эффекты, но каков будет функциональный способ справиться с такой же ситуацией?

Кроме того, если бы кто-нибудь мог указать мне на исходный код программы на Python или JavaScript, которая пытается быть максимально функциональной, это также было бы очень признательно.Я чувствую, что близок к тому, чтобы «понять это», но я еще не совсем там.В основном меня интересует, как функциональное программирование работает с традиционной концепцией классов ООП (или позволяет отказаться от нее в чем-то другом, если это так).

Это было полезно?

Решение

Вам следует прочитать этот вопрос:

Javascript как функциональный язык

Там много полезных ссылок, в том числе:

Теперь мое мнение.Много людей неправильно понимать JavaScript, возможно, потому, что его синтаксис похож на большинство других языков программирования (где Lisp/Haskell/OCaml выглядят совершенно по-другому).JavaScript — это нет объектно-ориентированный, это на самом деле язык, основанный на прототипах.В нем нет классов или классического наследования, поэтому его не следует сравнивать с Java или C++.

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

Возьмем пример (используя sys.puts из node.js):

var external;
function foo() {
    external = Math.random() * 1000;
}
foo();

sys.puts(external);

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

(function() {
    var external;
    function foo() {
        external = Math.random() * 1000;
    }
    foo();

    sys.puts(external);
})();

Обратите внимание, что на самом деле мы ничего не можем сделать с external или foo вне сферы действия.Они полностью заперты в своей замкнутости, неприкосновенны.

Теперь, чтобы избавиться от external побочный эффект:

(function() {
    function foo() {
        return Math.random() * 1000;
    }

    sys.puts(foo());
})();

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

Я также хочу отметить, что смешивание функционального программирования с объектами вполне допустимо.Возьмем это, например:

var Square = function(x, y, w, h) {
   this.x = x;
   this.y = y;
   this.w = w;
   this.h = h;
};

function getArea(square) {
    return square.w * square.h;
}

function sum(values) {
    var total = 0;

    values.forEach(function(value) {
        total += value;
    });

    return total;
}

sys.puts(sum([new Square(0, 0, 10, 10), new Square(5, 2, 30, 50), new Square(100, 40, 20, 19)].map(function(square) {
    return getArea(square);
})));

Как видите, использование объектов в функциональном языке может быть вполне приемлемым.В некоторых Лиспах даже есть так называемые списки свойств, которые можно рассматривать как объекты.

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

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

Другие советы

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

Функциональное программирование все дело в вычислениях без сохранения состояния. Объектно-ориентированного программирования все дело в переходах между состояниями.(Парафазировка этот.Надеюсь, не так уж и плохо)

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

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

Я стараюсь придерживаться следующих правил:

Функции, выполняющие вычисления, не должны изменять состояние.А функции, изменяющие состояние, не должны выполнять вычисления.Кроме того, функции, изменяющие состояние, должны изменять состояние как можно меньше.Цель состоит в том, чтобы иметь множество маленьких функций, которые делают только одну вещь.Затем, если вам нужно сделать что-то большое, вы составляете кучу маленьких функций, которые сделают то, что вам нужно.

Соблюдение этих правил дает ряд преимуществ:

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

  2. Надежность кода.Легче рассуждать о корректности кода, если он менее сложен.

  3. Функции легче тестировать, когда они делают только одно.Таким образом, будет меньше особых случаев для тестирования.

Обновлять:

Включено предложение из комментария.

Обновление 2:

Добавил несколько полезных ссылок.

Я думаю, http://documentcloud.github.com/underscore/ должен хорошо подходить для того, что вам нужно - он предоставляет наиболее важные функции высшего порядка для функционального программирования и не имеет клиентских функций для манипулирования DOM, которые вам не нужны на стороне сервера.Хотя у меня нет в этом опыта.

В качестве примечания:ИМХО, основной особенностью функционального программирования является Ссылочная прозрачность функции - результат функции зависит только от ее параметров - функция не зависит от изменений других объектов и не вносит никаких изменений, кроме своего значения результата.Это позволяет легко рассуждать о корректности программы и очень ценно для реализации предсказуемой многопоточности (если это необходимо).Хотя JavaScript не является лучшим языком для ФП, я ожидаю, что использование неизменяемых структур данных будет очень дорогим с точки зрения производительности.

Итак, 2 вещи, на которые стоит обратить внимание:

  1. В вашем первом примере ваша переменная не будет просачиваться в глобальную область, и так и должно быть, старайтесь никогда не использовать переменные без их объявления, т.е.test = 'data' приведет к утечке данных в глобальную область.

  2. Ваш второй пример также верен: bar1 и bar2 будут объявлены только для объекта Foo.

О чем следует помнить: старайтесь не злоупотреблять прототипированием, поскольку оно применяется к каждому объекту, который вы создаете. Это может потребовать очень много памяти, в зависимости от того, насколько сложны ваши объекты.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top