Понимание каталога функционального программирования JavaScript
- 0- Понимание функционального программирования JavaScript - что такое чистая функция
- 1- Понимание функционального программирования JavaScript - Каррирование
- 2- Понимание функционального программирования JavaScript - преимущества композиции кода
- 3- Понимание функционального программирования JavaScript — декларативные функции
- 4- Понимание функционального программирования на JavaScript — сигнатуры типов
кодовая комбинация
Код разведения
Объединение функций выглядит как строительные блоки. Вы ребенок, вы можете выбрать два строительных блока (функции) по желанию, дать им склеиться (сочетаться), и склеить их в новую игрушку (функция). Комбинации используются следующим образом:
var compose = function(f,g) {
return function(x) {
return f(g(x));
};
};
f
а такжеg
функции,x
это значение, которое "передается" между ними. Здесь следует отметить, что функция compose — самая важная часть идеи объединения кода, и она будет часто использоваться ниже. Вы можете отметить его заранее
var toUpperCase = function(x) { return x.toUpperCase(); };
var exclaim = function(x) { return x + '!'; };
var shout = compose(exclaim, toUpperCase);
shout("send in the clowns");
//=> "SEND IN THE CLOWNS!"
Таким образом мы объединяем две функции и возвращаем новую функцию.
Сравните комбинаторные функции
思考一下: 组合的函数和一个完整流程的函数有什么区别
var shout = function(x){
return exclaim(toUpperCase(x));
};
- Может быть разобран и объединен в другие модели LEGO.Можно видеть, что комбинированная функция может быть свободно объединена с другими доступными полными моделями моделей Lego (полностью функциональные функции), такими как игрушки Lego, но с полностью функциональной, неразъемной парой функций, как указано выше. Это как готовая фигура.
- Он не разбирается и был разработан, когда он покидает завод.
Понимание комбинированных кодов
Пусть код идет справа налево, а не изнутри наружу, я думаю, это можно назвать "левым крылом" (тишина~). Давайте рассмотрим пример, где порядок имеет значение:
var curry = require("lodash").curry;
var reduce = curry(function(f, init, arr){
return arr.reduce(f, init);
});
// 感谢掘友(@thsing772)提示,这里勘误一下 reduce 函数,应该是需要先 curry 处理一下,才能如下使用。
var head = function(x) { return x[0]; };
var reverse = reduce(function(acc, x){ return [x].concat(acc); }, []);
// 当然你也可以不使用 curry
// var reverse = x => x.reduce(function (arr,x){return [x].concat(ar)}[]);
var last = compose(head, reverse);
last(['jumpkick', 'roundhouse', 'uppercut']);
//=> 'uppercut'
Выше приведена операция обращения массива. Здесь мы видим, что комбинированная функция выполняется плавно. Мы можем активно оперировать функцией слева направо, но порядок выполнения справа налево больше соответствует математическому смыслу. Базовые математические знания средней школы
// 结合律(associativity)
var associative = compose(f, compose(g, h)) == compose(compose(f, g), h);
// true
compose(toUpperCase, compose(head, reverse));
// 或者
compose(compose(toUpperCase, head), reverse);
Преимущества ассоциативности
Преимущество ассоциативности состоит в том, что любую группу функций можно распаковать, а затем упаковать вместе в их собственную комбинацию для формирования новых функций. карри — наш инструментарий.
- Приведенные выше функции compose , head и reverse используются ниже.
var loudLastUpper = compose(exclaim, toUpperCase, head, reverse);
// 或
var last = compose(head, reverse);
var loudLastUpper = compose(exclaim, toUpperCase, last);
// 或
var last = compose(head, reverse);
var angry = compose(exclaim, toUpperCase);
var loudLastUpper = compose(angry, last);
// 更多变种...
бесточечный режим пустых данных
Безточечный режим означает режим без данных. Вот строчка из фильма «История любви» 70-х: «Любить — значит никогда не извиняться».
- Наша бесточечная модель: «Безточечный стиль означает, что вы никогда не говорите свои данные».
- Затем мы можем использовать каррирование и комбинирование кода для реализации следующих бесточечных стилей.
// 非 pointfree,因为提到了数据:word
var snakeCase = function (word) {
return word.toLowerCase().replace(/\s+/ig, '_');
};
// pointfree
var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);
// 不明白为什么看看最上面的 compose 函数,然后在 控制台试试 snakeCase 函数
snakeCase('Hello World')
// hello_world
В бесточечной версии слово параметр не требуется для построения функции, в бесточечной версии слово требуется для всех операций.
pointfree 模式能够帮助我们减少不必要的命名,让代码保持简洁和通用。
Распространенные проблемы отладки комбинированного кода~
Распространенной ошибкой при композиции является составление функции, такой как карта, которая принимает два аргумента до того, как не будет локального вызова.
// 下面部分函数来自于上面的 #### 结合律的好处
// 错误做法:我们传给了 `angry` 一个数组,根本不知道最后传给 `map` 的是什么东西。
var latin = compose(map, angry, reverse);
latin(["frog", "eyes"]);
// error
// 正确做法:每个函数都接受一个实际参数。
var latin = compose(map(angry), reverse);
latin(["frog", "eyes"]);
// ["EYES!", "FROG!"])
Используйте трассировку для отслеживания ваших функций
var trace = curry(function(tag, x){
console.log(tag, x);
return x;
});
var dasherize = compose(join('-'), toLower, split(' '), replace(/\s{2,}/ig, ' '));
dasherize('The world is a vampire');
// TypeError: Cannot read property 'apply' of undefined
--------------
// 看到报错了,来 trace 一下
var dasherize = compose(join('-'), toLower, trace("after split"), split(' '), replace(/\s{2,}/ig, ' '));
// after split [ 'The', 'world', 'is', 'a', 'vampire' ]
-------------
// tolower 的参数徐亚的是一个数组,所以这里我们 fix 一下我们的代码
var dasherize = compose(join('-'), map(toLower), split(' '), replace(/\s{2,}/ig, ' '));
dasherize('The world is a vampire');
// 'the-world-is-a-vampire'
Преимущество трассировки в том, что она может напрямую определить место, где вызывается функция, что позволяет нам наблюдать данные нашей функции в определенной точке.
Суммировать
Мы можем рассматривать композицию как принцип дизайна выше всех остальных принципов, потому что композиция делает наш код простым и читабельным. Кроме того, теория категорий будет играть важную роль в архитектуре приложений, моделировании побочных эффектов и обеспечении корректности.
Очки производных знаний: некоторая номенклатура
name | demo |
---|---|
CamelCase (маленький горб) | personId |
PascalCase (Паскаль/Большой горб) | PersonId |
SnakeCase (подчеркнуть) | person_id |
KebabCase (средняя линия) | person-id |