Вы освоили эти передовые функциональные техники?

внешний интерфейс
Вы освоили эти передовые функциональные техники?

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

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

Прочитайте последние популярные статьи брата А Бао (спасибо за вашу поддержку и поддержку 🌹🌹🌹):

Во-первых, высококачественные функции

В математике и информатике функция высшего порядка — это функция, которая удовлетворяет хотя бы одному из следующих условий:

  • принимает на вход одну или несколько функций;
  • Выведите функцию.

Получает на вход одну или несколько функций, т.е. функции передаются в качестве аргументов. Этот сценарий применения, как полагают, знаком многим людям. такие как обычно используемыеArray.prototype.map()а такжеArray.prototype.filter()Функции высшего порядка:

// Array.prototype.map 高阶函数
const array = [1, 2, 3, 4];
const map = array.map(x => x * 2); // [2, 4, 6, 8]

// Array.prototype.filter 高阶函数
const words = ['semlinker', 'kakuqo', 'lolo', 'abao'];
const result = words.filter(word => word.length > 5); // ["semlinker", "kakuqo"]

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

Следуйте «Дорога к бессмертному совершенствованию с полным стеком», чтобы прочитать 3 бесплатные электронные книги и 50 учебных пособий «Повторное изучение TS» от брата Абао.

Во-вторых, сочетание функций

Композиция функций — это процесс объединения двух или более функций для формирования новой функции:

const composeFn = function (f, g) {
  return function (x) {
    return f(g(x));
  };
};

В приведенном выше кодеfа такжеgявляются функциями, аxпараметры, которые объединяются для создания новой функции.

2.1 Роль функциональной композиции

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

Основываясь на вышеуказанных функциональных функциях, мы можем свободно комбинировать функции для достижения определенных функций:

function lowerCase(input) {
  return input && typeof input === "string" ? input.toLowerCase() : input;
}

function upperCase(input) {
  return input && typeof input === "string" ? input.toUpperCase() : input;
}

function trim(input) {
  return typeof input === "string" ? input.trim() : input;
}

function split(input, delimiter = ",") {
  return typeof input === "string" ? input.split(delimiter) : input;
}

// compose函数的实现,请参考 “组合函数的实现” 部分。
const trimLowerCaseAndSplit = compose(trim, lowerCase, split);
trimLowerCaseAndSplit(" a,B,C "); // ["a", "b", "c"]

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

2.2 Реализация комбинированных функций

function compose(...funcs) {
  return function (x) {
    return funcs.reduce(function (arg, fn) {
      return fn(arg);
    }, x);
  };
}

В приведенном выше коде мы передаемArray.prototype.reduceметод для реализации планирования комбинированных функций, и соответствующий порядок выполнения слева направо. Этот порядок выполнения соответствует порядку, в котором выполняются каналы или фильтры Linux.

Но если вы хотите начать выполнение справа налево, то вы можете использоватьArray.prototype.reduceRightметод достижения.

На самом деле, всякий раз, когда вы видитеcomposeфункция, брат Абао не мог не думать«Как лучше понять промежуточное ПО и луковую модель»описано в этой статьеcomposeфункция:

function compose(middleware) {
  // 省略部分代码
  return function (context, next) {
    let index = -1;
    return dispatch(0);
    function dispatch(i) {
      if (i <= index)
        return Promise.reject(new Error("next() called multiple times"));
      index = i;
      let fn = middleware[i];
      if (i === middleware.length) fn = next;
      if (!fn) return Promise.resolve();
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err);
      }
    }
  };
}

используя вышеизложенноеcomposeфункцию, мы можем реализовать следующий общий поток обработки задачи:

3. Карри

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

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

const func = function(a) {
  return function(b) {
    return a * a + b * b;
  }
}

func(3)(4); // 25

Uncurrying не является предметом этой статьи, далее мы используемLodashкоторый предоставилcurryФункция для интуитивного ощущения изменений после «каррирования» функции:

const abc = function(a, b, c) {
  return [a, b, c];
};
 
const curried = _.curry(abc);
 
curried(1)(2)(3); // => [1, 2, 3]
curried(1, 2)(3); // => [1, 2, 3]
curried(1, 2, 3); // => [1, 2, 3]

_.curry(func, [arity=func.length])

Создайте функцию, которая получаетfuncпараметры, либо вызовfuncрезультат возвращается, еслиfuncЕсли требуемые параметры были предоставлены, вернитесь напрямуюfuncрезультат исполнения. или вернуть функцию, которая принимает остальныеfuncфункцию с параметрами, вы можете использоватьfunc.lengthУстановите количество параметров для накопления.

источник:вооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооу

Здесь важно отметить, что в случае каррирования функций в математике и теоретической информатике за один раз может передаваться только один параметр. Для языка JavaScript каррированные функции в практических приложениях могут передавать один или несколько параметров.. Хорошо, после введения соответствующих знаний о каррировании, давайте представим функцию каррирования.

3.1 Роль карри

3.1.1 Повторное использование параметров
function buildUri(scheme, domain, path) {
  return `${scheme}://${domain}/${path}`;
}

const profilePath = buildUri("https", "github.com", "semlinker/semlinker");
const awesomeTsPath = buildUri("https", "github.com", "semlinker/awesome-typescript");

В приведенном выше коде сначала мы определяемbuildUriфункция, которую можно использовать для создания адреса uri. Затем мы используемbuildUriФункция строит AbaogeПерсональная домашняя страница Githubа такжеawesome-typescriptАдрес проекта. Для вышеуказанного адреса uri мы находимhttpsа такжеgithub.comДва значения параметров одинаковы.

Если нам нужно продолжить построение адресов других проектов Abaoge, нам нужно повторно установить одни и те же значения параметров. Так есть ли способ упростить этот процесс? Ответ да, даbuildUriФункция выполняет каррирование, и конкретный метод обработки выглядит следующим образом:

const _ = require("lodash");

const buildUriCurry = _.curry(buildUri);
const myGithubPath = buildUriCurry("https", "github.com");
const profilePath = myGithubPath("semlinker/semlinker");
const awesomeTsPath = myGithubPath("semlinker/awesome-typescript");
3.1.2 Ленивые вычисления/запуск
const add = function (a, b) {
  return a + b;
};

const curried = _.curry(add);
const plusOne = curried(1);

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

3.2 Реализация каррирования

Теперь мы знаем, что когда каррированная функция получает достаточное количество аргументов, она начинает выполнять исходную функцию. И если полученных параметров недостаточно, будет возвращена новая функция для получения оставшихся параметров. Основываясь на вышеперечисленных характеристиках, мы можем реализоватьcurryфункция:

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) { // 通过函数的length属性,来获取函数的形参个数
      return func.apply(this, args);
    } else {
      return function (...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  }
}

В-четвертых, применение частичной функции

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

Частичное приложение (Partial Application) легко спутать с каррированием функций, разница между ними заключается в следующем:

  • Применение частичной функции заключается в фиксации одного или нескольких параметров функции и возвращении функции, которая может получить остальные параметры;
  • Каррирование — это преобразование функции в несколько вложенных унарных функций, то есть каждая функция принимает только один параметр.

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

4.1 Использование частичных функций

function buildUri(scheme, domain, path) {
  return `${scheme}://${domain}/${path}`;
}

const myGithubPath = _.partial(buildUri, "https", "github.com");
const profilePath = myGithubPath("semlinker/semlinker");
const awesomeTsPath = myGithubPath("semlinker/awesome-typescript");

_.partial(func, [partials])

Создайте функцию. вызов функцииfuncИ нетерпеливыйpartialsпараметр.

источник:вооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооу

4.2 Реализация частичных функций

Частичные функции используются для исправления одного или нескольких параметров функции и возврата функции, которая может получить остальные параметры. Основываясь на вышеперечисленных характеристиках, мы можем реализоватьpartialфункция:

function partial(fn) {
  let args = [].slice.call(arguments, 1);
  return function () {
    const newArgs = args.concat([].slice.call(arguments));
    return fn.apply(this, newArgs);
  };
}

4.3 Частичная реализация функции и каррированная реализация

Пятая, инертная функция

Из-за некоторых проблем совместимости между различными браузерами нам необходимо принимать решения при использовании некоторых веб-API, таких как:

function addHandler(element, type, handler) {
  if (element.addEventListener) {
    element.addEventListener(type, handler, false);
  } else if (element.attachEvent) {
    element.attachEvent("on" + type, handler);
  } else {
    element["on" + type] = handler;
  }
}

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

5.1 Функции ленивой загрузки

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

function addHandler(element, type, handler) {
  if (element.addEventListener) {
    addHandler = function (element, type, handler) {
      element.addEventListener(type, handler, false);
    };
  } else if (element.attachEvent) {
    addHandler = function (element, type, handler) {
      element.attachEvent("on" + type, handler);
    };
  } else {
    addHandler = function (element, type, handler) {
      element["on" + type] = handler;
    };
  }
  // 保证首次调用能正常执行监听
  return addHandler(element, type, handler);
}

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

const addHandler = (function () {
  if (document.addEventListener) {
    return function (element, type, handler) {
      element.addEventListener(type, handler, false);
    };
  } else if (document.attachEvent) {
    return function (element, type, handler) {
      element.attachEvent("on" + type, handler);
    };
  } else {
    return function (element, type, handler) {
      element["on" + type] = handler;
    };
  }
})();

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

6. Функция кэширования

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

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

function memorize(fn) {
  const cache = Object.create(null); // 存储缓存数据的对象
  return function (...args) {
    const _args = JSON.stringify(args);
    return cache[_args] || (cache[_args] = fn.apply(fn, args));
  };
};

определенныйmemorizeПосле кэширования функции мы можем использовать ее так:

let complexCalc = (a, b) => {
  // 执行复杂的计算
};

let memoCalc = memorize(complexCalc);
memoCalc(666, 888);
memoCalc(666, 888); // 从缓存中获取

7. Справочные ресурсы