secretgspot
10/7/2019 - 3:15 AM

DECORATORS

/*
.__ .___ __ .__..__ .__..___..__..__  __.
|  \[__ /  `|  |[__)[__]  |  |  |[__)(__ 
|__/[___\__.|__||  \|  |  |  |__||  \.__)
*/

/* ▀▀▀ once()
once(fn): creates a version of the function that executes only once. 
It’s useful for an initialization function, where we want to make sure it 
runs only once, no matter how many times it is called from different places.
*/
function once(fn){
  let returnValue;
  let canRun = true;
  return function runOnce(){
      if(canRun) {
          returnValue = fn.apply(this, arguments);
          canRun = false;
      }
      return returnValue;
  }
}
var processonce = once(process);
processonce(); //process
processonce(); //



/* ▀▀▀ after()
after(count, fn): creates a version of the function that executes only after a 
number of calls. It’s useful, for example, when we want to make sure the 
function runs only after all the asynchronous tasks have finished.
*/
function after(count, fn){
   let runCount = 0;
   return function runAfter(){
      runCount = runCount + 1;
      if (runCount >= count) {
         return fn.apply(this, arguments);        
      }
   }
}
function logResult() { console.log("calls have finished"); }
let logResultAfter2Calls = after(2, logResult);
setTimeout(function logFirstCall() { 
      console.log("1st call has finished"); 
      logResultAfter2Calls(); 
}, 3000);
setTimeout(function logSecondCall() { 
      console.log("2nd call has finished"); 
      logResultAfter2Calls(); 
}, 4000);



/* ▀▀▀ throttle()
throttle(fn, wait): creates a version of the function that, when invoked 
repeatedly, will call the original function once per every wait milliseconds. 
It’s useful for limiting events that occur faster.
*/
function throttle(fn, interval) {
    let lastTime;
    return function throttled() {
        let timeSinceLastExecution = Date.now() - lastTime;
        if(!lastTime || (timeSinceLastExecution >= interval)) {
            fn.apply(this, arguments);
            lastTime = Date.now();
        }
    };
}
let throttledProcess = throttle(process, 1000);
$(window).mousemove(throttledProcess);



/* ▀▀▀ debounce()
debounce(fn, wait): creates a version of the function that, when invoked 
repeatedly, will call the original function after wait milliseconds since the 
last invocation. It’s useful for running a function only after the event has stopped arriving.
*/
function debounce(fn, interval) {
    let timer;
    return function debounced() {
        clearTimeout(timer);
        let args = arguments;
        let that = this;
        timer = setTimeout(function callOriginalFn() {
             fn.apply(that, args);
        }, interval);
    };
}
let delayProcess = debounce(process, 400);
$(window).resize(delayProcess);



/* ▀▀▀ partial()
Now let’s create the partial() method that will be available for all functions. 
This time I use the ECMAScript 6 rest parameters syntax ...leftArguments instead 
of the arguments object as I want to concatenate arrays and arguments is not an array object.
*/
Function.prototype.partial = function(...leftArguments){
    let fn = this;
    return function partialFn(...rightArguments){
       let args = leftArguments.concat(rightArguments);
       return fn.apply(this, args);
    }
}
function log(level, message){
    console.log(level  + " : " + message);
}
let logInfo = log.partial("Info");
logInfo("here is a message");