Coriolization of JavaScript function

  • 2021-12-04 18:00:54
  • OfStack

Directory 1 What is the function Corrigenation2 What is the function and feature of Corrigenation2. 1 Parameter multiplexe2. 2 Return early 2.3 Delay execution 3 Encapsulate the generic Corrigenization tool function # 4 Summary and supplement

1 What is Currization of Functions

In computer science, Currification ( Currying ) is the technique of transforming a function that accepts multiple parameters into a function that accepts a single 1 parameter (the first parameter of the original function) and returns a new function that accepts the remaining parameters and returns the result Haskell Curry Named.

What do you mean? Simply put, Currization is a technique used to transform multi-parameter functions.

For example:


//  This is 1 Acceptance 3 A function with three parameters 
const add = function(x, y, z) {
  return x + y + z
}


If we transform it by 1, we can get such a function:


//  Receive 1 Single order 1 Parameter 
const curryingAdd = function(x) {
  //  And returns the function that accepts the remaining arguments 
  return function(y, z) {
    return x + y + z
  }
}


What difference does this make? Compare from the call:


//  Call add
add(1, 2, 3)
 
//  Call curryingAdd
curryingAdd(1)(2, 3)
//  See more clearly 1 Point, equivalent to the following 
const fn = curryingAdd(1)
fn(2, 3)

As you can see, the transformed function can accept parameters in batches. Remember this point first, which will be useful below. Even fn ( curryingAdd The function returned) can also continue to transform

As follows:


const curryingAdd = function(x) {
  return function(y) {
    return function(z) {
      return x + y + z
    }
  }
}
//  Call 
curryingAdd(1)(2)(3)
//  I.e. 
const fn = curryingAdd(1)
const fn1 = fn(2)
fn1(3)

The above two transformations are the Curritization of functions.

Simply put, it is to put a multi-parameter function f Transformed into a function that accepts some parameters g And this function g Returns 1 function h The function h is used to accept other parameters. The function h can continue Currization. It is the process of a doll ~

So what's the use of going to so much trouble to Corrigenize the function?

The function and characteristics of Corrigenization

2.1 Parameter multiplexing

Requirements encountered in work: Check whether the telephone number, email address and ID card are legal through regularity, etc.

So we encapsulate a check function as follows:


/**
 * @description  Verify the string through regularity 
 * @param {RegExp} regExp  Regular object 
 * @param {String} str  String to be verified 
 * @return {Boolean}  Whether it passes the verification 
 */
function checkByRegExp(regExp, str) {
    return regExp.test(str)
}

If we want to check a lot of mobile phone numbers and mailboxes, we will call like this:


//  Check the mobile phone number 
checkByRegExp(/^1\d{10}$/, '15152525634'); 
checkByRegExp(/^1\d{10}$/, '13456574566'); 
checkByRegExp(/^1\d{10}$/, '18123787385'); 
//  Verify mailbox 
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'fsds@163.com'); 
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'fdsf@qq.com'); 
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'fjks@qq.com');

It seems that there is no problem, but in fact there is still room for improvement

When checking the data of the same type 1, we write the same regularity many times. The code is poorly readable. If there is no comment, we can't see the effect of regularity in one time

We try to use functional Curritization to improve:


//  Curritization of a function 
function checkByRegExp(regExp) {
    return function(str) {
        return regExp.test(str)
    }
}


So we pass in different regular objects, and we can get functions with different functions:


//  Check mobile phone 
const checkPhone = curryingCheckByRegExp(/^1\d{10}$/)
//  Verify mailbox 
const checkEmail = curryingCheckByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/)


Now it is easier to check the code of mobile phone and email, and the readability is enhanced


//  Check the mobile phone number 
checkPhone('15152525634'); 
checkPhone('13456574566'); 
checkPhone('18123787385'); 
//  Verify mailbox 
checkEmail('fsds@163.com'); 
checkEmail('fdsf@qq.com'); 
checkEmail('fjks@qq.com');

This is parameter reuse: we just need to put the first parameter regExp Reuse, you can directly call functions with specific functions

Generic functions such as checkByRegExp ) solves the compatibility problem, but it also brings inconvenience to use, for example, different application scenarios need to pass multiple different parameters to solve the problem

Sometimes the same rule may be used repeatedly (such as checking the parameters of mobile phones), which leads to code repetition. Currization can eliminate repetition and achieve the purpose of reusing parameters.

An important thought of Corrigendum: reducing the scope of application and improving the applicability

2.2 Early return

In JS DOM In the event listener, we use Haskell Curry 0 Method to add an event handler to the element, but some browser versions do not support this method, we will use the attachEvent Method to replace.

At this time, we will write a code compatible with each browser version:


/**
 * @description: 
 * @param {object} element DOM Element object 
 * @param {string} type  Event type 
 * @param {Function} fn  Event handler 
 * @param {boolean} isCapture  Capture or not 
 * @return {void}
 */
function addEvent(element, type, fn, isCapture) {
    if (window.addEventListener) {
        element.addEventListener(type, fn, isCapture)
    } else if (window.attachEvent) {
        element.attachEvent("on" + type, fn)
    }
}

We use addEvent To add event listening, but every time this method is called, a judgment will be made. In fact, after the browser version is determined, there is no need to repeat the judgment.

Currification treatment:


//  Receive 1 Single order 1 Parameter 
const curryingAdd = function(x) {
  //  And returns the function that accepts the remaining arguments 
  return function(y, z) {
    return x + y + z
  }
}


0

What we get now addEvent It is a function obtained after judgment, so there is no need to repeat judgment when calling it later.

This is to return in advance or confirm in advance. After curitization, functions can handle some tasks in advance and return 1 function to handle other tasks

In addition, we can see that, curryingAddEvent It seems that the parameters are not accepted. This is because of the condition of the primitive function (that is, whether the browser version supports it or not Haskell Curry 0 ) is obtained directly from the global.

Logically, it can actually be changed to:


//  Receive 1 Single order 1 Parameter 
const curryingAdd = function(x) {
  //  And returns the function that accepts the remaining arguments 
  return function(y, z) {
    return x + y + z
  }
}


1

Of course there is no need to change this ~

2.3 Delayed execution

In fact, the above example of regular checksum event listening already reflects the delayed execution.

curryingCheckByRegExp After the function is called, it returns checkPhone And checkEmail Function

curringAddEvent After the function is called, it returns addEvent Function

None of the returned functions will be executed immediately, but will wait for the call.

3 Encapsulate the Universal Currization Tool Function #

Above, we modified the original function manually by Curritization of the function, which will add Changed to curryingAdd , will checkByRegExp Changed to curryingCheckByRegExp , will addEvent Changed to curryingAddEvent .

Do we have to manually modify the underlying function every time we Curritization the function? Of course not

We can encapsulate a general Coriolian tool function (interview handwritten code)


//  Receive 1 Single order 1 Parameter 
const curryingAdd = function(x) {
  //  And returns the function that accepts the remaining arguments 
  return function(y, z) {
    return x + y + z
  }
}


2

This Currization tool function is used to receive some parameters, then returns a new function waiting to receive the remaining parameters, recursively until all the required parameters are received, and then passes apply Call the original function.

Now we basically don't have to modify the original function manually to Currize the function


//  Directly use the tool function to return the function to check the mobile phone and mailbox 
const checkPhone = currying(checkByRegExp(/^1\d{10}$/))
const checkEmail = currying(checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/))


However, the above example of event monitoring can't be Corrified by this tool function. As mentioned earlier, because its conditions are directly obtained from the global situation, it is quite special. If the conditions are passed in from the outside, it can be Corrified by the tool function. Of course, this is not necessary. It is more direct and readable to modify the original function directly

4 Summary and supplement

Currihua highlights one important thought: reducing the scope of application and improving the applicability Three functions and characteristics of Currization: parameter reuse, early return and delayed execution Currization is a typical application of closure, which forms a scope stored in memory by using closure, and saves some received parameters in this scope, waiting for subsequent use. And returns a new function to receive the remaining arguments

Related articles: