Ето няколко декоративни функции, които можете да пишете от нулата

Открийте Функционалния JavaScript беше обявен за една от най-добрите нови книги за функционално програмиране от BookAuthority!

Снимка на Calum Lewis на Unsplash
Функцията декоратор е функция от по-висок ред, която приема една функция като аргумент и връща друга функция, а върнатата функция е разновидност на аргументната функция - Javascript Allongé

Нека да напишем някои общи декоратори на функции, открити в библиотеки като underscore.js, lodash.js или ramda.js.

веднъж()

  • веднъж (fn): създава версия на функцията, която се изпълнява само веднъж. Полезно е за функция за инициализация, при която искаме да се уверим, че тя работи само веднъж, независимо колко пъти е извикана от различни места.
функция веднъж (fn) {
  нека returnValue;
  нека canRun = true;
  функция за връщане runOnce () {
      ако (canRun) {
          returnValue = fn.apply (това, аргументи);
          canRun = невярно;
      }
      return returnValue;
  }
}
var processonce = веднъж (процес);
processonce (); // процес
processonce (); //

Once () е функция, която връща друга функция. Върнатата функция runOnce () е затваряне. Също така е важно да се отбележи как се нарича оригиналната функция - чрез предаване на текущата стойност на този и всички аргументи: fn.apply (това, аргументи).

Ако искате да разберете по-добре затварянията, разгледайте защо трябва да дадете още един шанс на функцията за закриване.

след()

  • after (count, fn): създава версия на функцията, която се изпълнява само след редица обаждания. Полезно е например, когато искаме да се уверим, че функцията работи само след приключване на всички асинхронни задачи.
функция след (брой, fn) {
   нека runCount = 0;
   функция за връщане runAfter () {
      runCount = runCount + 1;
      ако (runCount> = брой) {
         върнете fn.apply (това, аргументи);
      }
   }
}
функция logResult () {console.log ("разговорите приключиха"); }
нека logResultAfter2Calls = след (2, logResult);
setTimeout (функция logFirstCall () {
      console.log ("1-вият разговор приключи");
      logResultAfter2Calls ();
}, 3000);
setTimeout (функция logSecondCall () {
      console.log ("2-рото обаждане приключи");
      logResultAfter2Calls ();
}, 4000);

Обърнете внимание как използвам след () за изграждане на нова функция logResultAfter2Calls (), която ще изпълни оригиналния код на logResult () едва след второто повикване.

дросел()

  • дросел (fn, изчакване): създава версия на функцията, която при извикване многократно ще извиква оригиналната функция веднъж на всеки милисекунда чакане. Полезно е за ограничаване на събития, които се случват по-бързо.
функция газ (fn, интервал) {
    нека lastTime;
    функция за връщане заглушена () {
        нека timeSinceLastExecution = Date.now () - lastTime;
        if (! lastTime || (timeSinceLastExecution> = interval)) {
            fn.apply (това, аргументи);
            lastTime = Date.now ();
        }
    };
}
нека throttledProcess = дросел (процес, 1000);
$ (Прозорец) .mousemove (throttledProcess);

В този пример, придвижването на мишката ще генерира много събития за движение на мишката, но извикването на оригиналния процес на функция () просто ще се случи веднъж в секунда.

debounce ()

  • debounce (fn, изчакайте): създава версия на функцията, която при многократно извикване ще извика оригиналната функция след изчакване милисекунди от последното извикване. Полезно е да стартирате функция само след като събитието е спряло да пристига.
функция разобръщане (fn, интервал) {
    нека таймер;
    функция за връщане дебютиран () {
        clearTimeout (таймер);
        нека args = аргументи;
        нека това = това;
        timer = setTimeout (функция callOriginalFn () {
             fn.apply (това, args);
        }, интервал);
    };
}
нека delayProcess = debounce (процес, 400);
$ (Прозорец) .resize (delayProcess);

Някои често срещани събития, които трябва да вземете предвид, са превъртане, промяна на размера, движение на мишката или натискане на клавиш.

Частично приложение

Частичното приложение се отнася до процеса на фиксиране на редица аргументи на функция.

Това е начин да се премине от обобщение към специализация.

частичен ()

Сега нека създадем метода частичен (), който ще бъде наличен за всички функции. Този път използвам синтаксиса на параметрите за почивка на ECMAScript 6 ... leftArguments вместо аргумента обект, тъй като искам да обединявам масиви и аргументите не са обект от масив.

Function.prototype.partial = функция (... leftArguments) {
    нека fn = това;
    функция за връщане частFn (... rightArguments) {
       нека args = leftArguments.concat (rightArguments);
       върнете fn.apply (това, args);
    }
}
дневник на функциите (ниво, съобщение) {
    console.log (ниво + ":" + съобщение);
}
нека logInfo = log.partial ("Инфо");
logInfo ("тук е съобщение");

Забележете как изградихме функцията logInfo (), която сега изисква само един параметър (съобщение).

заключение

Изпълнението на тези общи функции ни помага по-добре да разберем как работи декоратор, а също така ни дава представа за вида на логиката, която може да капсулира.

Функционалните декоратори са мощен инструмент за създаване на вариации на съществуващи функции без промяна на оригиналните функции. Те могат да бъдат част от инструменталния набор от функционални програми за повторна употреба на обща логика.

Открийте Функционалния JavaScript беше обявен за една от най-добрите нови книги за функционално програмиране от BookAuthority!

За повече информация относно прилагането на техники за функционално програмиране в React, разгледайте Functional React.

Прочетете повече за Vue и Vuex в Бързо въведение към Vue.js Components.

Научете как да прилагате принципите на моделите за дизайн.

Можете да ме намерите и в Twitter.