Как выкладывается функциональное приложение JavaScript на основе программирования?
Я работал с node.js некоторое время в приложении чата (я знаю, очень оригинально, но я понял это был бы хороший учебный проект). Underscore.js предоставляет множество концепций функционального программирования, которые выглядят интересными, поэтому я хотел бы понять, как будет настраиваться функциональная программа в JavaScript.
Из моего понимания функционального программирования (что может быть неправильно) вся идея состоит в том, чтобы избежать побочных эффектов, которые в основном имеют функцию, которая обновляет другую переменную вне функции, поэтому что-то вроде
var external;
function foo() {
external = 'bar';
}
foo();
будет создавать побочный эффект, правильно? Поэтому, как правило, вы хотите избежать нарушения переменных в глобальной области.
Хорошо, так как это работает, когда вы имеете дело с объектами, а что нет? Например, много раз у меня будет конструктор и метод init, который инициализирует объект, например:
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 программы, которая пытается быть настолько функциональной, насколько это возможно, это также очень ценится. Я чувствую, что я близок к тому, чтобы "получить это", но я просто не совсем там. В основном меня интересует, как функциональное программирование работает с традиционной концепцией классов ООП (или устраняет это для чего-то другого, если это так).
Ответы
Ответ 1
Вы должны прочитать этот вопрос:
Javascript как функциональный язык
Есть много полезных ссылок, в том числе:
Теперь, по моему мнению. Многие люди неправильно понимают JavaScript, возможно потому, что его синтаксис похож на большинство других языков программирования (где Lisp/Haskell/OCaml выглядят совершенно иначе), JavaScript не является объектно-ориентированным, это фактически язык прототипа. У него нет классов или классического наследования, поэтому его нельзя сравнивать с Java или С++.
JavaScript может быть лучше по сравнению с Lisp; он имеет замыкания и первоклассные функции. Используя их, вы можете создавать другие методы функционального программирования, такие как частичное приложение (currying).
Возьмем пример (используя 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);
})));
Как вы можете видеть, использование объектов на функциональном языке может быть очень хорошим. Некоторые Lisps даже имеют вещи, называемые списками свойств, которые можно рассматривать как объекты.
Реальный трюк с использованием объектов в функциональном стиле заключается в том, чтобы убедиться, что вы не полагаетесь на их побочные эффекты, но вместо этого считаете их неизменными. Легкий способ - всякий раз, когда вы хотите изменить свойство, просто создайте новый объект с новыми деталями и вместо этого передайте его (это подход, который часто используется в Clojure и Haskell).
Я твердо верю, что функциональные аспекты могут быть очень полезны в JavaScript, но в конечном итоге вы должны использовать все, что делает код более читаемым и что работает для вас.
Ответ 2
Вы должны понимать, что функциональное программирование и объектно-ориентированное программирование несколько противоречат друг другу. Невозможно, чтобы оба были чисто функциональными и чисто объектно-ориентированными.
Функциональное программирование - это все вычисления без учета состояния. Объектно-ориентированное программирование - это все о переходах состояний. (Paraphasing this. Надеюсь, что не так уж плохо)
JavaScript более объектно ориентирован, чем функциональный. Это означает, что если вы хотите программировать в чисто функциональном стиле, вам нужно отказаться от больших частей языка. В частности, все объектно-ориентированные части.
Если вы хотите быть более прагматичным в этом отношении, есть некоторые вдохновения из чисто функционального мира, который вы могли бы использовать.
Я стараюсь придерживаться следующих правил:
Функции, выполняющие вычисления, не должны изменять состояние. И функции, которые изменяют состояние, не должны выполнять вычисления. Кроме того, функции, которые изменяют состояние, должны изменяться как можно меньше состояний. Цель состоит в том, чтобы иметь множество маленьких функций, которые делают только одно. Затем, если вам нужно сделать что-нибудь большое, вы создаете кучу небольших функций, чтобы делать то, что вам нужно.
Из следующих правил можно извлечь ряд преимуществ:
-
Простота повторного использования. Чем дольше и сложнее функция, тем она более специализирована и, следовательно, тем менее вероятно, что ее можно повторно использовать. Обратное следствие состоит в том, что более короткие функции имеют тенденцию к более общим и, следовательно, более легким для повторного использования.
-
Надежность кода. Легче рассуждать о правильности кода, если он менее сложный.
-
Легче тестировать функции, когда они делают только одно. Таким образом, для тестирования требуется меньше особых случаев.
Update:
Встроенное предложение из комментария.
Обновление 2:
Добавлены полезные ссылки.
Ответ 3
Я думаю, http://documentcloud.github.com/underscore/ должно быть хорошо подходить под то, что вам нужно - он обеспечивает наиболее важные функции более высокого порядка для функционального программирования и не имеет клиентских функций для манипуляций с DOM, которые вам не нужны на стороне сервера. Хотя у меня нет опыта с этим.
В качестве побочного примечания: основной функцией функционального программирования IMHO является Ссылочная прозрачность результата функции - функция зависит только от ее параметров - функции не зависит от изменений на других объектах и не вносит никаких изменений, кроме значения результата. Это позволяет легко рассуждать о правильности программы и очень ценно для реализации предсказуемой многопоточности (если это необходимо). Хотя JavaScript не является языком ставок для FP - я ожидаю, что неизменяемые структуры данных будут очень дорогими, чтобы использовать их.
Ответ 4
Итак, нужно отметить 2 вещи,
-
В вашем первом примере ваша переменная не будет протекать в глобальную область и как она должна быть выполнена, старайтесь никогда не использовать переменные без объявления их, т.е. test = 'data' приведет к утечке данных в глобальной области.
-
Второй пример также правильный, bar1 и bar2 будут объявлены только на объекте Foo.
Следует помнить, что вы не должны чрезмерно использовать прототипирование, поскольку оно применяется к каждому созданному вами объекту, это может быть чрезвычайно интенсивным в памяти в зависимости от того, насколько сложны ваши объекты.
Если вы ищете инфраструктуру разработки приложений, посмотрите ExtJs. Лично я думаю, что это прекрасно впишется в модель, против которой вы пытаетесь развиваться. Просто имейте в виду, как работает их модель лицензирования, прежде чем вкладывать в нее значительные средства.