Как устроено функциональное приложение JavaScript на основе программирования?
Вопрос
я работал с узел.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.
- Маленький JavaScripter
- JavaScript высшего порядка
- Красноречивый JavaScript, глава 6:Функциональное программирование
Теперь мое мнение.Много людей неправильно понимать 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 более объектно-ориентирован, чем функционален.Это означает, что если вы хотите программировать в чисто функциональном стиле, вам придется отказаться от значительной части языка.В частности, все объектно-ориентированные части.
Если вы готовы подойти к этому более прагматично, вы можете использовать некоторые идеи из чисто функционального мира.
Я стараюсь придерживаться следующих правил:
Функции, выполняющие вычисления, не должны изменять состояние.А функции, изменяющие состояние, не должны выполнять вычисления.Кроме того, функции, изменяющие состояние, должны изменять состояние как можно меньше.Цель состоит в том, чтобы иметь множество маленьких функций, которые делают только одну вещь.Затем, если вам нужно сделать что-то большое, вы составляете кучу маленьких функций, которые сделают то, что вам нужно.
Соблюдение этих правил дает ряд преимуществ:
Простота повторного использования.Чем длиннее и сложнее функция, тем она более специализирована и, следовательно, тем меньше вероятность ее повторного использования.Обратный вывод заключается в том, что более короткие функции имеют тенденцию быть более универсальными и, следовательно, их легче использовать повторно.
Надежность кода.Легче рассуждать о корректности кода, если он менее сложен.
Функции легче тестировать, когда они делают только одно.Таким образом, будет меньше особых случаев для тестирования.
Обновлять:
Включено предложение из комментария.
Обновление 2:
Добавил несколько полезных ссылок.
Я думаю, http://documentcloud.github.com/underscore/ должен хорошо подходить для того, что вам нужно - он предоставляет наиболее важные функции высшего порядка для функционального программирования и не имеет клиентских функций для манипулирования DOM, которые вам не нужны на стороне сервера.Хотя у меня нет в этом опыта.
В качестве примечания:ИМХО, основной особенностью функционального программирования является Ссылочная прозрачность функции - результат функции зависит только от ее параметров - функция не зависит от изменений других объектов и не вносит никаких изменений, кроме своего значения результата.Это позволяет легко рассуждать о корректности программы и очень ценно для реализации предсказуемой многопоточности (если это необходимо).Хотя JavaScript не является лучшим языком для ФП, я ожидаю, что использование неизменяемых структур данных будет очень дорогим с точки зрения производительности.
Итак, 2 вещи, на которые стоит обратить внимание:
В вашем первом примере ваша переменная не будет просачиваться в глобальную область, и так и должно быть, старайтесь никогда не использовать переменные без их объявления, т.е.test = 'data' приведет к утечке данных в глобальную область.
Ваш второй пример также верен: bar1 и bar2 будут объявлены только для объекта Foo.
О чем следует помнить: старайтесь не злоупотреблять прототипированием, поскольку оно применяется к каждому объекту, который вы создаете. Это может потребовать очень много памяти, в зависимости от того, насколько сложны ваши объекты.
Если вы ищете среду разработки приложений, взгляните на ExtJs.Лично я думаю, что это идеально вписывается в модель, которую вы пытаетесь разработать.Просто имейте в виду, как работает их модель лицензирования, прежде чем вкладывать в нее значительные средства.