foreword
In the process of learning JavaScript, we may have more or less exposure to higher-order functions. So, do we have a clear definition for this ourselves, or are we very proficient in mastering these usages?
If there are any flaws or mistakes in the article, please give me more advice from the friends who see it, thank you in advance
Below↓
In simple terms, a higher-order function is a function that receives a function as an argument or returns a function as an outputWhen you see such a concept, what functions will appear in your mind?
In fact, some array methods that we often use, such as: map, filter, etc. are all categories of higher-order functions
Of course, these built-in methods in JavaScript are not within the scope of this article. Here are some high-level usages of functions that we may encounter during actual development or interviews.
anti-shake
When tasks are triggered frequently, the task will be executed only when the interval between task triggers exceeds the specified interval.The implementation method is that if the frequency of task triggering is less than the time we set, then we will clear the previous task and re-time it.
function debounce(fn, interval) { let timer = null return function() { // If the user triggers again within the set time, it will be cleared clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, arguments) }, interval); } }
throttling
The task will only be executed once within the specified time intervalfunction throttle(fn, interval) { let timer, firstTime = true // Is it the first execution return function () { let _this = this if (firstTime) { fn.apply(_this, arguments) // No need to delay execution the first time return firstTime = false } if (timer) { // If the timer is still, it means that the previous one has not been executed. return false } timer = setTimeout(() => { clearTimeout(timer) timer = null fn.apply(_this, arguments) }, interval || 500); } } // Add a throttle directly without considering the timer function throttle(fn, interval) { let canRun = true //throttle valve return function() { if(!canRun) { return } canRun = false setTimeout(() => { fn.apply(this, arguments) canRun = true }, interval); } }
Whether it is anti-shake or throttling, we can use the following method to verify
window.onresize = throttle(function () { console.log(1) }, 1000)
Through the implementation of the above two methods, I believe that my friends also understand that the so-called anti-shake and throttling are achieved by means of setTimeOut, the difference is the position of clearing the timer
lazy function
When we need to reuse a logic, optimize logic judgment and improve JavaScript performancePrinciple: Override the function of the same name
function createXHR() { var xhr try { xhr = new XMLHttpRequest() } catch (e) { handleErr(e) try { xhr = new ActiveXObject('Msxml2.XMLHTTP') } catch (e) { try { xhr = new ActiveXObject('Microsoft.XMLHTTP') } catch (e) { xhr = null } } } return xhr } function handleErr(e) { // do sth }
Modified version of lazy function:
function createXHR() { var xhr if(typeof XMLHttpRequest !== 'undefined') { xhr = new XMLHttpRequest() createXHR = function() { return new XMLHttpRequest() } } else { try { xhr = new ActiveXObject('Msxml2.XMLHTTP') createXHR = function() { return new ActiveXObject('Msxml2.XMLHTTP') } } catch(e) { try { xhr = new ActiveXObject('Microsoft.XMLHTTP') createXHR = function() { return new ActiveXObject('Microsoft.XMLHTTP') } } catch(e) { createXHR = function() { return null } } } } return xhr }
After the above modification, when we call this function for the first time, we will judge the current environment, and then optimize the abbreviation of the function, and do not need to make subsequent judgments.
For example, if the XMLHTTPRequest in the above code exists, then when we call this function for the second time, it is already like this
function createXHR() { return new XMLHttpRequest() }
scenes to be used:
- Frequent use of the same judgment logic
- Only need to judge once, the subsequent use environment is stable
cascade function
In fact, it is a chain call, so the principle is very simple: return the object itself in each method
Suppose we have a Person template
function Person() {} // add a few methods Person.prototype = { setName: function (name) { this.name = name return this // }, setAge: function (age) { this.age = age return this }, setSex: function (sex) { this.sex = sex }, } // Don't forget to re-specify the constructor Person.constructor = Person let person = new Person() // This seems to do a lot of repetitive things. With a little modification, the effect of chaining calls can be achieved by returning this in each method. person.setName('wandering de tadpole') person.setAge(18) person.setSex('male') // after modification person.setName('wandering de tadpole').setAge(18).setSex('male') console.log(person)
Advantage: Simplifies the steps of function calls, we don't need to write some repetitive things
Disadvantage: occupies the return value of the function
Pea resource search sitehttps://55wd.com Computer Embroidery Embroidery Factory ttp://www.szhdn.com
Currying
Collect parameters and delay execution, also known as partial evaluationfunction add(a, b) { return a + b } // Simple generic package function curry(fn) { let args = Array.prototype.slice.call(arguments, 1) return function() { let _args = Array.prototype.slice.call(arguments) let final = args.concat(_args) return fn.apply(null, final) } } // Curry the function add let adder = curry(add) adder(1, 2) // or let adder = curry(add, 1)(2) let adder = curry(add)(1, 2)
A typical general-purpose curry package
Function.prototype.mybind = function(fn) { let args = Array.prototype.slice(arguments, 1) let _this = this return function() { let _args = Array.prototype.slice(arguments) let final = args.concat(_args) return _this.apply(fn, final) } }
Through this pattern of curry functions, we can implement a simple bind
Function.prototype.mybind = function(fn) { let _this = this return function() { return _this.apply(fn, arguments) } }
Function currying is also a problem we may often encounter during the interview process, such as:
// Write an add function that implements the following functions add(1)(2)(3) // 6 add(1)(2, 3)(4) //10 add(1, 2)(3) (4, 5) // 15 function add() { let args = Array.prototype.slice.call(arguments) let adder = function() { // Use closures to save args and collect parameters args = args.concat(Array.prototype.slice.call(arguments)) return adder } // Returns the final computed value using the toString feature of implicit conversion adder.toString = function() { return args.reduce((a, b) => { return a + b }) } return adder } add(1)(2)(3) // 6 add(1)(2, 3)(4) // 10 add(1, 2)(3)(4, 5) // 15 // Of course, we can also simplify this function with the help of ES6 methods function add1(...args) { let adder = (..._args) => { args = [...args, ..._args] return adder } adder.toString = () => args.reduce((a, b) => a + b) return adder }
To achieve the effect of the above function, I think there are two points that we must understand and master:
- Closures, use the characteristics of closures to save and collect the parameters we need
- Using the implicit conversion feature of toString, we finally get the result we want a