Начинающий JavaScript OOP vs Functional

Я только начинаю изучать разные стили программирования (ООП, функциональные, процедурные).

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

_.map([1, 2, 3], function(n){ return n * 2; });
_([1, 2, 3]).map(function(n){ return n * 2; });

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

Ответ 1

Нет правильного определения того, что есть и не является "функциональным", но в целом функциональные языки делают упор на простоту, когда речь идет о данных и функциях.

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

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

function compose(f, g) {
  return function(data) {
    return f(g(data));
  }
}

const flatMap = compose(_.flatten, _.map);

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

В любом случае стиль общего функционального программирования заключается в том, что данные должны быть последним аргументом функции, что упрощает каррирование или частичное применение более ранних аргументов. Lodash/fp и ramda адресуйте это, указав следующая подпись для карты.

_.map(func, data);

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

const double = x => x * 2;
const mapDouble = _.map(double);

mapDouble([1, 2, 3]);
// => [2, 4, 6]

Ответ 2

Парадигма программирования

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

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

Теперь, когда вы немного понимаете, что такое парадигма программирования (надеюсь), давайте кратко рассмотрим основы OOP и FP.

Объектно-ориентированное программирование

В ООП объект - это блок, содержащий информацию и операции, которые должны ссылаться на одну и ту же концепцию. Информация часто называется "атрибутами", а операции часто называются "методами". Атрибуты позволяют отслеживать состояние объекта, а методы позволяют манипулировать состоянием объекта.

В JS вы можете отправить сообщение объекту для выполнения определенного метода. Приведенный ниже код показывает, как вызвать метод в JS. У "точечного" объекта есть два атрибута, "x" и "y", и метод, называемый "translate". Метод "translate" обновляет координаты "point" на основе заданного вектора.

point = {
  x: 10, y: 10,
  translate: function (vector) {
    this.x += vector.x;
    this.y += vector.y;
  }
};

point.x; // 10
point.translate({ x: 10, y: 0 });
point.x; // 20

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

Функциональное программирование

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

На самом деле JS может использоваться как язык FP, если вы позаботитесь о побочных эффектах, для этого нет встроенного механизма. Следующий код является примером такого стиля программирования. Функция "zipWith" происходит из мира Haskell. Он объединяет два списка, используя данную функцию, как это происходит, add(point[i], vector[i]).

zipWith = function (f, as, bs) {
  if (as.length == 0) return [];
  if (bs.length == 0) return [];
  return [f(as[0], bs[0])].concat(
    zipWith(f, as.slice(1), bs.slice(1))
  );
};

add = function (a, b) {
  return a + b;
};

translate = function (point, vector) {
  return zipWith(add, point, vector);
};

point = [10, 10];
point[0]; // 10
point = translate(point, [10, 0]);
point[0]; // 20

Это определение очень поверхностно, хотя. Например, Haskell, который является чисто функциональным языком, реализует множество других понятий, таких как композиция функций, функторы, карри, монады и т.д.

Заключение

На самом деле ООП и ФП - это две разные концепции, которые не имеют ничего общего, я бы даже сказал, что сравнивать не с чем. Таким образом, я считаю, что то, что вы прочитали из документации Underscore.js, является неправильным использованием языка.

Вы не должны изучать парадигмы программирования в рамках этой библиотеки. Действительно, то, как вы пишете код с помощью Underscore.js, делает его похожим на ООП и FP, но это только вопрос внешнего вида. Следовательно, под капотом нет ничего действительно захватывающего :-)


Обратитесь к Википедии для углубленного чтения.

Ответ 3

Функциональный: Вы передаете объект функции и делаете вещи

_.map([1, 2, 3], function(n){ return n * 2; });

ООП: Вы вызываете функцию на объект и делаете вещи

_([1, 2, 3]).map(function(n){ return n * 2; });

В обоих примерах [1,2,3] (array) - объект.

Пример ссылки OOP: http://underscorejs.org/#times

Ответ 4

FP

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

Мы покажем минимальную реализацию map в FP и ООП. В этом примере FP ниже обратите внимание на то, как map работает только с локальными переменными и не зависит от состояния -

const _ = {
                 // 🡣 has two parameters
  map: function (arr, fn) {
      // 🡣 local
    if (arr.length === 0)
      return []
    else
            // 🡣 local               
                // 🡣 local           // 🡣 local    // 🡣 local
      return [ fn(arr[0]) ].concat(_.map(arr.slice(1), fn))
  }
}

const result =
  // 🡣 call _.map with two arguments
  _.map([1, 2, 3], function(n){ return n * 2; })


console.log(result)
// [ 2, 4, 6 ]

Ответ 5

Строго говоря, оба они - ООП. Однако первый метод (_.map) также называется функцией полезности. Функция представляет собой метод объекта _, но оператор не создает новый экземпляр конструктора _, и значение возвращается после вызова метода. Поскольку возвращаемое значение является объектом Array, вы также можете вызвать все методы массива на нем. Это означает, что он все еще OOP, потому что в JavaScript почти все является объектом.

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

В основном этот абзац означает, что в первом фрагменте не создается объект подчеркивания, а во втором фрагменте под сценой создается объект подчеркивания.

Здесь ООП/функционал относится к стилистической, а не прагматической перспективе разработчика JavaScript.

Ответ 6

Оба map являются функциональными, и оба кода основаны на значении concpet, value = > по карте.

Однако, оба они также могут быть видны как ООП, так как стиль object.map.

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