Javascript is your higher order function of advanced application

  • 2020-06-15 07:37:55
  • OfStack

In normal programming languages, functions can only take arguments of primitive types or object references and return values of primitive data types or object references. However, in Javascript, functions are citizens of class 1 and can be passed as arguments or returned as return values. Higher-order functions are those that take a function as an argument or return a value. These two situations have many application scenarios in actual development. This paper is a summary of several application scenarios I have encountered in my work and study.

The callback function

Code reuse is one of the most important criteria for measuring an application. The code reuse rate can be improved by separating the changing business logic into callback functions. For example, the forEach method added to the array in ES5 iterates through several groups, calling the same function on each element.


array = {};
array.forEach = function(arr, fn){
  for (var i = 0, len = arr.length; i < len; i++) {
    fn(arr[i], i, arr);
  }
}

Callbacks are used to focus the business on callbacks instead of having to write and iterate through the code each time.

Partial function

A typical application of output as a function as a return value is a partial function. A partial function is the use of a function that creates a function that calls another part, a function with a preset parameter or variable. I don't understand what this is doing looking at the definition. So let's start with an example, and the most typical example of a partial function is a type judgment.

Javascript objects have three properties: prototype, class, and extensibility. page: 138) class attribute is a string, which is not directly provided in Javascript, but we can use Object.prototype.toString to get it indirectly. This function always returns the following:

[object Class]

So we can write a series 1 of isType functions.

The code is as follows:


isString = function(obj){
  return Object.prototype.toString.call(obj) === "[object String]";
}
isNumber = function(obj){
  return Object.prototype.toString.call(obj) === "[object Number]";
}
isArray = function(obj){
  return Object.prototype.toString.call(obj) === "[object Array]";
}

Most of the code in these functions is repetitive, and this is where higher-order functions come in:


isType = function(type) {
  return function(obj) {
    return Object.prototype.toString.call(obj) === "[object " + type + "]";
  }
}

isString = isType('String');
isNumber = isType('Number');
isArray = isType('Array');

So the return of a new custom function by specifying a partial parameter is a partial function.

currying (Coriolis)

currying is also known as partial evaluation. An currying function first takes 1 argument, and after accepting these arguments, the function does not immediately evaluate, but continues to return another function, the arguments just passed are stored in the closure formed by the function. By the time the function really needs to be valued, all the arguments passed in will be evaluated by the first degree.


var currying = function(fn) {
  var args = [];
  
  return function() {
    if (arguments.length === 0) {
      return fn.applay(this, args);
    } else {
      args = args.concat(arguments);
      return arguments.callee;
    }
  }
}

Let's take the example of calculating daily expenses for a month:


var currying = function(fn) {
debugger;
  var args = [];
  
  return function() {
    if (arguments.length === 0) {
      return fn.apply(this, args);
    } else {
      Array.prototype.push.apply(args, arguments);
      return arguments.callee;
    }
  }
}

cost = function(){
  var sum = 0;
  for (var i = 0, len = arguments.length; i < len; i++) {
    sum += arguments[i];
  }
  
  return sum;
}
var cost = currying(cost);

cost(100);
cost(200);
alert(cost())

Event throttling

In some scenarios, certain events may be triggered repeatedly, but the event handler does not need to be executed every time. For example, complex logic calculation in window.resize event will seriously affect the performance if the user changes the browser size frequently. Sometimes these logical calculations do not need to be fired every time for rezise, but only a limited number of times. We need to ignore 1 event request based on the time period. See the following throttle function:


function throttle(fn, interval) {
   var doing = false;

   return function() {
    if (doing) {
     return;
    }
    doing = true;
    fn.apply(this, arguments);
    setTimeout(function() {
     doing = false;
    }, interval);
   }
  }
  
  window.onresize = throttle(function(){
    console.log('execute');
  }, 500);

By controlling the execution time of the function, you can achieve a perfect balance between the number of function executions and the functional requirements. The other event is mousemove. If we bind this event to an dom element, it will be triggered repeatedly as the mouse moves over the element.

End of the event

For events that can be triggered frequently, sometimes we want to do a series 1 after the event is over. In this case, we can use the higher-order function to do the following processing:


function debounce(fn, interval) {
  var timer = null;

 function delay() {
  var target = this;
  var args = arguments;
  return setTimeout(function(){
   fn.apply(target, args);
  }, interval);
 }

 return function() {
  if (timer) {
   clearTimeout(timer);
  }

  timer = delay.apply(this, arguments);
 }
};
window.onresize = throttle(function(){
  console.log('resize end');
}, 500);

If an event is triggered during this process, the last event handle is cleared and the execution time is re-bound.

Resources:

node

Javascript Design Patterns and Development Practices


Related articles: