This is the 31st day of my participation in the August Text Challenge.More challenges in August

preface

Currie, originally is a form of function in mathematics, the extended to computer science, is to accept multiple parameters functions to accept a single parameter, and returns a function, these functions accept the rest of the parameters, is actually used before closure to keep the incoming parameters, makes the subsequent function can be used directly. In JS, currization is the foundation of functional programming.

A simple chestnut

To better understand currization, here is a summation function to illustrate the currization process:

function sum(a, b, c) {
    return a + b + c; 
}
Copy the code

According to the properties of currization, it can be known that:

sum(1.2.3) = sum(1) (2) (3) = sum(1.2) (3) = sum(1) (2.3) 
Copy the code

It is obvious that sum returns a function after curryification, and that the state of the passed arguments must be saved for the return function call, which uses closures. For example, a call to sum(1) returns a function that already has argument 1, and subsequent calls to the function continue to use argument 1 to calculate the result.

The simplest implementation code for Currie is as follows:

function sum(a) { 
  return function(b) {
    return function(c) {
        return a+b+c
    };
  };
}
Copy the code

The code above is the simplest implementation of sum(1,2,3) = sum(1)(2)(3), but it is often wrapped in a wrapper function by passing in a function and returning a currified function, such as _. Curry in lodash.

Let’s use the Currified packaging function to transform sum:

function curry(f) { 
  return function(a) {
    return function(b) {
        return function(c) {
          return f(a, b, c);
        };
    };
  };
}

function sum(a, b, c) {
  return a + b + c;
}

let curriedSum = curry(sum);
console.log(curriedSum(1) (2) (3))/ / 6
Copy the code

Although the encapsulation of the Corrification wrapper is realized, it is not enough. It can only pass in 1 function at a time, and cannot realize the free combination of parameters, so it cannot be regarded as a complete Corrification.

A few more refines to implement a wrapper for a multi-parameter Coriolization function.

// Currize wrapper
function curry(func) {
  return function curried(. args) { / / 1
    if (args.length >= func.length) { / / 2
      return func.apply(this, args);
    } else { / / 3
      return function(. args2) { //4c
        return curried.apply(this, args.concat(args2)); }}}; }Copy the code
  1. The job of the Currie wrapper is to currie a function and return it
  2. If the number of parameters of the new function is greater than or equal to the number of parameters of the original function (Function,length), then execute directly, corresponding toThe sum (1, 2, 3) = curriedSum (1, 2, 3)
  3. Otherwise, the currified function is recursively called, returning a function that holds the last passed argument.
function sum(a, b, c) {
  return a + b + c;
}

let curriedSum = curry(sum);

alert( curriedSum(1.2.3));// 3 arguments, equivalent to calling sum directly
alert( curriedSum(1) (2.3));// 6, currization of the first argument
alert( curriedSum(1) (2) (3));// 6, full cremation
Copy the code

Application scenarios

The sum function above is just a demonstration of the Curryization process, but it is actually one use of curryization: delayed execution. In practice, currification is mainly used for parameter reuse, compatibility processing, delay execution and so on. Although the currie function is obviously more complex, it improves the applicability of the function.

Parameters of reuse

For example, if we want to encapsulate a function that initiates an Ajax request, there are multiple method types in the request, and we can encapsulate these methods separately, but a lot of the logic in the request is reusable, so we can use the currization of the function.

function request(method,url,payload){
    const xhr = new new XMLHttpRequest(...)
    xhr.open(method, url, true); 
    xhr.send(payload);
}

function curriedRequest(method){
    return function(url,payload){
        const xhr = new new XMLHttpRequest(...)
        xhr.open(method, url, true); xhr.send(payload); }}Copy the code

The method argument is reused, and it can return functions that are applicable to different types of requests.

const getAjax = curriedRequest('GET')
const postAjax = curriedRequest('POST')

postAjax('www.example.com'.JSON.stringify({... }))/ *... * /
Copy the code

Feature detection and compatibility processing

Due to the development of browsers and other reasons, some functions and methods are not supported by some browsers, and the code we write needs to cover the majority of the population, so we need to make a judgment in advance to determine whether the user’s browser supports the relevant methods, and then polyfill the methods that are not supported. For example, addEventListener and attchEvent are two ways to register listeners, respectively. AttchEvent is only implemented in lower versions of IE, so we need to create a function to determine the two.

const whichEvent = ( function () {
    // addEventListener is preferred
    if(window.addEventListener){
        return function(element,type,listener,useCapture){
            element.addEventListener(type,function(e){
                listener.call(element,e);
            },useCapture);
        }
    // Determine the attchEvent in IE
    }else if(window.attchEvent){
        return function(element,type,handler){
            element.attchEvent('on'+element,function(e){ handler.call(element,e); }); }}}) ();Copy the code