Это 4-й день моего участия в августовском испытании обновлений.Подробности о событии:Испытание августовского обновления.
предисловие
карриа такжечастичная функцияВсе они являются важными понятиями функционального программирования.Давайте сегодня взглянем на них с другой стороны.антикарринг.
Но так как он против каррирования, давайте сначала познакомимся с его сестрой.Каррирование и частичные функции.
Каррирование и частичные функции
1.1 Каррирование
Википедия говорит:
Каррирование, английский язык: Каррирование — это метод преобразования функции, которая принимает несколько параметров, в функцию, которая принимает один параметр (первый параметр исходной функции) и возвращает новую функцию, которая принимает остальные параметры и возвращает результат.
Эта техника была разработана логиком Кристофером Стрейчи.Haskell Curryназван, хотя он был изобретен Моисеем Шнфинкелем и Готтлобом Фреге.
Давайте рассмотрим пример, который более нагляден:
function sum(a, b, c) {
return a + b + c;
}
function currySum(a){
return function (b){
return function (c){
return a + b + c;
}
}
}
sum(1,2,3) // 6
currySum(1)(2)(3) // 6
Всего два момента:
-
Многопараметрический проход
-
Возвращаемая функция, если условие выполнено, должна выполнить функцию и вернуть результат
1.1.1 Трудности
Сложность общих функций каррирования заключается в том, как узнатьдлина аргументов функции, Обычно используемые методы:
-
Function.prototype.length
свойство получить длину параметраНедостаток,остальные параметры не учитываются в длине.
Следующий код, полученная длина которого равна 2, является лучшим фактом.
function log(msg1, msg2, ...other){ console.log(msg1, msg2, ...other); } console.log(log.length); // 2
-
При каррировании отображалась длина входящего параметра
-
Конечно, их можно комбинировать, и значение функции по умолчанию в порядке.
function curry(fn, length = fn.length){ // .... }
1.1.2 Заполнители
После каррики, концепция нескольких заполнителей, что это значит, то есть я не буду сначала пройти этот параметр, а затем передать его позже.
Взгляните на официальный пример lodash.
var abc = function(a, b, c) {
return [a, b, c];
};
var curried = _.curry(abc);
// Curried with placeholders.
curried(1)(_, 3)(2);
// => [1, 2, 3]
Что касается реализации, расширенная версияlodash.curry, гражданская версияКаррирование функций в темах JavaScript.
1.2 Частичная функция
Подобно каррированию, просто понять, что параметры передаются дважды.
- Исправлены некоторые параметры впервые
- Второй проход по остальным параметрам
Посмотрите на официальный пример подчеркивания, в этом примере тоже есть заполнители, но это не влияет на понимание.
var subtract = function(a, b) { return b - a; };
sub5 = _.partial(subtract, 5);
sub5(20);
=> 15
// Using a placeholder
subFrom20 = _.partial(subtract, _, 20);
subFrom20(5);
=> 15
Что касается реализации, расширенная версияlodash.partialтак же какunderscore.partial, плохой вариантЧастичная функция javaScript тема
Здесь функция частичной функцииbind
Есть сходства.
Однако сегодня в центре внимания не они, а борьба с каррированием.
антикарринг
2.1 Концепция
Антикарринг – этоВсевозможность, брать чужие вещи и пользоваться ими.
Давайте рассмотрим пример: мы часто используем для определения типа данныхObject.prototype.toString
function unCurry(fn) {
return function (context) {
return fn.apply(context, Array.prototype.slice.call(arguments, 1));
}
}
// 不使用反柯里化
Object.prototype.toString.call({}); // [object Object]
// 反柯里化
const toString = unCurry(Object.prototype.toString);
toString({}); // [object Object]
toString(() => { }); // [object Function]
toString(1); // [object Number]
2.2 Реализация
2.2.1 Базовая версия: простая и понятная
function unCurry(fn) {
return function (context) {
return fn.apply(context, Array.prototype.slice.call(arguments, 1));
}
}
2.2.2 Прототип: Вторжение + Удобство
Function.prototype.unCurry = function(){
var self = this;
return function(){
return Function.prototype.call.apply(self, arguments);
}
}
Эта версия взломает прототип, который мне не нравится. Удобство все еще там.
Две трудности в понимании
-
self = this
self равен самой функции, вот онавременная функция -
Function.prototype.call.apply(self, arguments)
Говоря о проблемах, обратите внимание на следующее преобразование.
Function.prototype.call.apply(self, arguments)
==>
Function.prototype.call.bind(self)(arguments)
==>
self.call(arguments)
==>
self.call(arguments[0], arguments[1-n]) // arguments[0]就是self函数的上下文了
Если вы используете его, он немного изменится
2.2.3 Прототип 2.
Я не буду это интерпретировать, каждый сам разберется
Function.prototype.unCurry = function () {
return this.call.bind(this);
};
Возможен ли следующий код с ES6?
Function.prototype.unCurry = function () {
return (...args) => this.call(...args)
};
Есть еще множество интересных способов письма, для более подробной информации см.# Carrying && Anti-Carrying
2.3 Сценарии использования
Антикаррирование — это идея, и ее реализацию определенно можно заменить другими решениями.Но еще один способ мышления означает еще один метод.
2.3.1 Оценка типа данных
Демонстрация выше была продемонстрирована.
2.3.2 Проталкивание массива (пример в расширенном программировании)
const push = unCurry(Array.prototype.push);
const arr = [1, 2, 3];
push(arr, 4, 5, 6);
console.log(arr);
2.3.3 Массив репликации
const clone = unCurry(Array.prototype.slice);
var a = [1,2,3];
var b = clone(a);
console.log("a==b", a === b); // a==b false
console.log(a, b); // [ 1, 2, 3 ] [ 1, 2, 3 ]
2.3.4 Отправка событий
const dispatch = unCurry(EventTarget.prototype.dispatchEvent);
window.addEventListener("event-x", (ev) => {
console.log("event-x", ev.detail); // event-x ok
})
dispatch(window, new CustomEvent("event-x", { detail: "ok" }));
Подробно объясните каррирование функций JS