preface
To understand what functional Corrification is, you need to know functional programming; Functional programming is a way of programming in which functions are passed and returned as arguments without side effects; Functional programming also introduces many concepts, and functional currification is just a pattern in functional programming, a generalization of the concept.
- Pure functions: simply return new values without changing system variables;
- 1. An operation that converts a function that takes more than one parameter into a function that takes a single parameter;
- Higher-order function: A function that can take a function as an argument and even return a function
What is the Currization of a function
A function called currying is also called partial evaluation. A function that curries will first take some arguments. After taking these arguments, the function will not immediately evaluate, but will continue to return another function, and the arguments that were passed will be stored in the closure formed by the function. When the function is actually asked for a value, all the arguments passed in before are used to evaluate it at once.
It is generally said that currization is the operation of converting a function of several variables into a low component function
A closure is a function that reads variables inside other functions, so a closure can be understood as a function defined inside a function.
Case analysis and explanation
To start with a common encapsulation of functionality, we know that there are four ways to determine the type of a variable:
- Typeof {} returns “object”; typeof {} returns “object”.
- Constructor can find out by whom this variable is constructed [].constructor ({}).constructor
- Instanceof an instanceof judging who is who,proto
- Object.prototype.toString.call()
The fourth method can judge all data types, even null and undefined. So we consider wrapping it so that it can be called
Encapsulate the type determination function type
Simple packaging
function isType(type,value) {
return Object.prototype.toString.call(value) === `[object ${type}] `
}
isType('Array'[]),// true
isType('Array', {}) // false
isType('String'.'str') // true
Copy the code
After the above simple encapsulation, it seems to be more convenient to use, but there is a problem, that is, if the target type is written incorrectly, it will be inaccurate judgment everywhere, how to solve it?
Solve the problem of inaccurate judgment caused by incorrect input
Solution 1: Throw an exception
const typeArr = ['String'.'Number'.'Boolean'.'Array'.'Symbol'.'Null'.'Undefined'.'Function'.'Object'.'Arguments']
function isType(type,value) {
if(! typeArr.includes(type)) {throw(`${type} is not in ${typeArr}`)}return Object.prototype.toString.call(value) === `[object ${type}] `
}
Copy the code
Disadvantages: Although it solves the problem of inaccurate judgment caused by handwriting errors, the problem is also obvious.
- The first one is that multiple parameters still need to be input when using, which is not friendly to use. Multiple judgment of the same type requires repeated input of relevant target types.
- The second needs to cover all the right types, not generalities;
IsArray ([]),isString(‘xx’), isString(‘xx’)
Solution two: Corrification
function isType(type) {
return function(value) {
return Object.prototype.toString.call(value) === `[object ${type}] `}}/ / define
const isArray = isType('Array')
const isString = isString('String')
/ / use
console.log(isArray([])) // true
console.log(isArray('1234')) // false
console.log(isString('1234')) // true
console.log(isString(1234)) // false
Copy the code
So that we can define the corresponding methods for the several types we need to use frequently;
Induction and extension
Look closely at the relationship between the Currified function and the uncurrified simple function
// Uncurrified function
function isType(type,value) {
return Object.prototype.toString.call(value) === `[object ${type}] `
}
// The use of uncorrified functions
isType('Array'[]),// true
Copy the code
// The currie function
function isType(type) {
return function(value) {
return Object.prototype.toString.call(value) === `[object ${type}] `}}// Use it after currization
const isArray = isType('Array')
console.log(isArray([]))
/ / is equivalent to
console.log(isType('Array') ([]))Copy the code
By comparison, it can be found that the original call requiring two parameters (‘Array’, []) has been changed to pass one parameter (‘Array’) to return a function to receive the next parameter ([]).
If we return a function that has only two parameters, we will need to nest multiple parameters. We want each parameter to be passed in separately, so that arguments that can be used multiple times over a fixed line can be encapsulated again. Is it possible to implement a general Currie function to implement a Currie method?
General Purpose Corrified function encapsulation
Here is an example with more parameters
function sum(a,b,c,d,e) {
return a + b + c + d + e
}
sum(1.2.3.4.5)
Copy the code
Sum takes five arguments, and we want it to be called like isType(‘Array’)([]) above
function sum(a,b,c,d,e) {
return a + b + c + d + e
}
// General-purpose currization
function currying(fn) {
//
return function () {
// }}const getSum = currying(sum)
console.log(getSum(1) (2.3) (4) (5))
/ / or
currying(sum)(1) (2.3) (4) (5)
Copy the code
Each pass is not guaranteed to return the desired result until all five are passed
Open dry
function currying(fn, arr = []) {
// (function(a,b,c,d,e) {}). Length Gets the number of parameters passed to the function
let fnParamsLen = fn.length
// Higher order function
return function (. args) {
let concatArr = [...arr, ...args]
if (concatArr.length < fnParamsLen) {
// Recursively generate functions continuously
return currying(fn, concatArr)
} else {
returnfn(... concatArr) } } }/ / test
// 1. 5 Parameter sum
const getSum = currying(function (a,b,c,d,e) {
return a + b + c + d + e
})
console.log(getSum(1) (2.3) (4) (5)) / / 15
// 2
const getType = currying(function (type,value) {
return Object.prototype.toString.call(value) === `[object ${type}] `
})
console.log(getType('Array') (' ')) // false
console.log(getType('Array') ([]))// true
Copy the code
Extensions · Encapsulate AJAX GET and POST requests
For GET and POST requests that encapsulate Ajax, each request requires the request type type to be passed in, so consider currification to fix this parameter
function Ajax() {
this.xhr = new XMLHttpRequest()
}
// Core processor
Ajax.prototype.open = function(type,url,data,callback) {
this.onload = function() {
callback(this.xhr.responseText, this.xhr.status, this.xhr)
}
this.xhr.open(type, url, data.async);
this.xhr.send(data.paras);
}
// Push a get POST method into memory, passing in the fixed first argument type, which is get and POST respectively
'get post'.split(' ').forEach(function(type) {
Ajax.prototype[type] = currying(Ajax.prototype.open,type)
})
var xhr1 = new Ajax()
// Call the currified function, passing in the remaining parameters URL,data, and callback
xhr1.get(url,data,callback)
var xhr2 = new Ajax();
xhr2.post(url,data,callback);
Copy the code
In conclusion, Currization is an application of functional chain programming that involves closures, so its disadvantages are obvious, as summarized below
Advantages: 1. Single entrance, easy to test and reuse; 2. It is easy to locate the bug and determine which parameter is faulty in which link.
Disadvantages: Nested functions take up memory, which is inefficient. After all, each function generates a separate scope and occupies a chunk of memory in the call stack.