предисловие
Каррирование, которое можно понимать какПолучить некоторые параметры заранее, отложить выполнение, не выводить результат сразу, а вернуть функцию, которая принимает остальные параметры. Из-за этой характеристики ее также называют функцией частичного расчета. Каррирование — это пошаговый процесс получения параметров. В следующем анализе вы глубоко оцените это.
Антикаррирование — этоОбобщениепроцесс. Это позволяет декаррированной функции бытьполучить больше параметров. Цель состоит в том, чтобы создать более общую функцию, которая может использоваться различными объектами. Создается впечатление, что голубь занимает гнездо сороки.
1. Карри
1.1 Пример
выполнитьadd(1)(2, 3)(4)() = 10
Эффект
По смыслу названия следует отметить два ключевых момента:
- При передаче параметров код не выполняет результат вывода, а сначала запоминает его
- Когда передается пустой параметр, это означает, что реальная операция может быть выполнена
Полный код выглядит следующим образом:
function currying(fn){
var allArgs = [];
return function next(){
var args = [].slice.call(arguments);
if(args.length > 0){
allArgs = allArgs.concat(args);
return next;
}else{
return fn.apply(null, allArgs);
}
}
}
var add = currying(function(){
var sum = 0;
for(var i = 0; i < arguments.length; i++){
sum += arguments[i];
}
return sum;
});
1.2 Запоминание входящих параметров
Поскольку это результат вычисления с задержкой, необходимо запомнить параметры.
Способ сделать это здесь — использовать замыкания.
function currying(fn){
var allArgs = [];
return function next(){
var args = [].slice.call(arguments);
if(args.length > 0){
allArgs = allArgs.concat(args);
return next;
}
}
}
при исполненииvar add = currying(...)
час,add
переменная уже указывает наnext
метод. В настоящее время,allArgs
существуетnext
Внутри метода есть ссылка, поэтому он не может быть переработан сборщиком мусора. То есть,allArgs
После выполнения оператора присваивания он существует и образует замыкание.
Опираясь на эту функцию, до тех пор, пока полученные параметры непрерывно вводятся вallArgs
переменная для хранения.
Так когдаarguments.length > 0
, вы можете поместить полученные новые параметры вallArgs
середина.
последнее возвращениеnext
Указатели функций, образующие цепочки вызовов.
1.3 Оценка условий выполнения триггерной функции
Значение вопросов, пустые параметры, выходной результат. Так что, пока судьяarguments.length == 0
выполнить.
Кроме того, из-за способа вычисления результата он передается как параметрcurrying
функция, поэтому используйтеapply
выполнить.
Комбинируя приведенные выше соображения, можно получить следующую полную функцию каррирования.
function currying(fn){
var allArgs = []; // 用来接收参数
return function next(){
var args = [].slice.call(arguments);
// 判断是否执行计算
if(args.length > 0){
allArgs = allArgs.concat(args); // 收集传入的参数,进行缓存
return next;
}else{
return fn.apply(null, allArgs); // 符合执行条件,执行计算
}
}
}
1.4 Резюме
Каррирование, четкий кодекс поведения можно увидеть в этом примере:
- Получайте параметры шаг за шагом и кэшируйте их для последующего вычисления
- Не рассчитывайте сразу, отложите выполнение
- Если условия расчета соблюдены, кэшированные параметры равномерно передаются методу выполнения.
1.5 Расширение
выполнитьadd(1)(2, 3)(4)(5) = 15
Эффект.
Тут многие бормочут: Откуда мне знать время казни?
Собственно, вот навык ниндзя:valueOf
а такжеtoString
.
Когда js получает текущее значение переменной, он будет неявно вызываться в соответствии с контекстом.valueOf
а такжеtoString
способ получения нужного значения.
Тогда это очень просто реализовать.
function currying(fn){
var allArgs = [];
function next(){
var args = [].slice.call(arguments);
allArgs = allArgs.concat(args);
return next;
}
// 字符类型
next.toString = function(){
return fn.apply(null, allArgs);
};
// 数值类型
next.valueOf = function(){
return fn.apply(null, allArgs);
}
return next;
}
var add = currying(function(){
var sum = 0;
for(var i = 0; i < arguments.length; i++){
sum += arguments[i];
}
return sum;
});
2. Защита от каррирования
2.1 Пример
Существуют следующие классы легких подсказок. теперь хочу использовать его в одиночкуshow
метод, который выводит новый объектobj
содержание в .
// 轻提示
function Toast(option){
this.prompt = '';
}
Toast.prototype = {
constructor: Toast,
// 输出提示
show: function(){
console.log(this.prompt);
}
};
// 新对象
var obj = {
prompt: '新对象'
};
Вы можете сделать это антикарринговым способом
function unCurrying(fn){
return function(){
var args = [].slice.call(arguments);
var that = args.shift();
return fn.apply(that, args);
}
}
var objShow = unCurrying(Toast.prototype.show);
objShow(obj); // 输出"新对象"
2.2 Антикарринговое поведение
- Не мой, для моего
- Увеличить параметры, полученные методом антикарринга
В приведенном выше примереToast.prototype.show
метод, это былToast
приватные методы класса. следить за новым объектомobj
Нет полцентовых отношений.
После антикаррирования это может бытьobj
Используемые объекты.
Почему может бытьobj
Используется, потому что внутреннийToast.prototype.show
Контекст переопределяется какobj
. то есть использоватьapply
измененныйthis
направление.
В процессе достижения этого шага необходимо усилить антикоринизацию.objShow
параметры метода.
2.3 Еще одна реализация антикарринга
Function.prototype.unCurrying = function(){
var self = this;
return function(){
return Function.prototype.call.apply(self, arguments);
}
}
// 使用
var objShow = Toast.prototype.show.unCurrying();
objShow(obj);
Трудность здесь состоит в том, чтобы понятьFunction.prototype.call.apply(self, arguments);
.
Его можно разделить на два этапа:
1)Function.prototype.call.apply(...)
Анализ
можно рассматривать какcallFunction.apply(...)
. Таким образом, это намного яснее.
callFunction
изthis
указатель, поapply
превратиться вself
.
затем выполнитьcallFunction
-> callFunction(arguments)
2)callFunction(arguments)
Анализ
call
метод, первый параметр, используется для указанияthis
из. такcallFunction(arguments)
-> callFunction(arguments[0], arguments[1-n])
.
Отсюда можно сделать вывод, что после антикаррирования первый параметр используется для указанияthis
указал на.
3)Зачем использовать apply(я, аргументы)При использованииapply(null, arguments)
,потому чтоnull
объект неcall
метод, будет сообщено об ошибке.
3. Настоящий бой
3.1 Оценка типов переменных (антикаррирование)
var fn = function(){};
var val = 1;
if(Object.prototype.toString.call(fn) == '[object Function]'){
console.log(`${fn} is function.`);
}
if(Object.prototype.toString.call(val) == '[object Number]'){
console.log(`${val} is number.`);
}
Приведенный выше код с использованием антикаррирования можно записать так:
var fn = function(){};
var val = 1;
var toString = Object.prototype.toString.unCurrying();
if(toString(fn) == '[object Function]'){
console.log(`${fn} is function.`);
}
if(toString(val) == '[object Number]'){
console.log(`${val} is number.`);
}
3.2 Прослушивание событий (каррирование)
function nodeListen(node, eventName){
return function(fn){
node.addEventListener(eventName, function(){
fn.apply(this, Array.prototype.slice.call(arguments));
}, false);
}
}
var bodyClickListen = nodeListen(document.body, 'click');
bodyClickListen(function(){
console.log('first listen');
});
bodyClickListen(function(){
console.log('second listen');
});
Используйте каррирование для оптимизации прослушивания событий узла DOM.addEventListener
Эти три параметра не нужно записывать каждый раз.
постскриптум
По сути, антикаррирование — это то же самое, что и универсальные методы, но есть некоторые различия в концепции. Поймите этот тип мышления.
Друзья, которым нравятся мои статьи, могут подписаться на меня следующими способами:
- "звезда"или"смотреть"мойGitHub blog
- RSS-канал моего личного блога:База мистера Вана