Writing in the front
It seems that spring recruitment is approaching recently, and I am hesitant to try my resume. Around a lot of big guy, cast resume of cast resume, interview of interview, very panic. But, panic, panic, learning to continue. I heard that some basic questions may be asked in the interview, such as handwritten Promise and handwritten bind. These two problems, learning process encountered, just take advantage of this opportunity to review.
This article will be based on their own practice to explain the principle of BIND function, and simple code to simulate BIND. Assuming you already know about call/apply, let’s take a look at the corrification of the function before we begin:
The function is currified
The concept is not repeated, but to put it succinctly, a function is passed parameters in advance (preexecution). In fact, it is customized parameters according to the requirements to achieve special effects. Look at the code:
/** * Currification function * @param preArgs [list of arguments to bind] * @returnThe Currie function */functioncurry(fn, ... preArgs){return function(... Args){// Concatenate external and predefined parameters in order and pass in the target functionreturnfn.call(null, ... preArgs, ... args) } }Copy the code
As you can see, the return value of The Curry function is a function, which means that the target function we passed into the Curry function has not been executed. What special effect does this achieve?
// Target functionfunction add (a, b) {
returnCurry (add, 7) cosnt addWith_7 = curry(add, 7) Here 7 + 1 = 8 addWith_7(1) // => 8Copy the code
The currified object function add results in a function (addWith_7) with some pre-configured parameters, but the object function is not executed. And since 7 is passed in advance, the addWith_7 function only needs to pass in one argument to do its job of adding 7. It’s a customization.
Fn. call(null,… preArgs, … Args) execute the target function without a bound scope, and you can expect more fancy uses if you do.
The bind function
demand
In browsers, we often need to bind events to buttons:
// Get the buttonlet btn = document.getElementById('button') // Event handlersfunction print (e) {
console.log(e)
console.log(this)
}
Copy the code
Bind the event to the button, click the button, and print the event object and this
btn.addEventListener('click'.print) // Prints out the event object and the event.target objectCopy the code
This in the event handler points to event.target by default. If I want this to point to a custom scope and output content, I need to change the scope of the function to this point. There are only two call/apply functions that can change what this refers to. You might think:
btn.addEventListener("click", print.call(context)) // This is obviously wrongCopy the code
The call/apply call will execute the function, and we can indeed change this, but the target function is also executed. Event handling requires a callback function that is called only when the event is triggered. Obviously, call/ Apply doesn’t cut it for us.
When you think of curry’s function, let’s tweak it a little bit and add the context parameter:
// Add the context argumentfunctioncurry(context, fn, ... preArgs){return function(... Args){// Concatenate external and predefined parameters in order and pass in the target functionreturnfn.call(context, ... preArgs, ... Args)}} // Sample scopelet context = {
name: "This is the example scope"} // Example functionslet print = function () {
console.log(this.name)
}
let target = curry(context, printTarget () // =>'This is the example scope'
Copy the code
As you can see, the scope of our print function is changed, but it is not executed immediately, but after we execute target. Isn’t that right?
btn.addEventListener('click', curry(context, print) // Perfect solution!Copy the code
This modification proved necessary to make function calls more flexible.
To realize the bind
Curry is already ready to serve as a bind Function, but it needs to be added to the Function prototype for ease of use so that one parameter, the target Function, is omitted.
Attention! You can’t add attributes or methods to built-in objects during development, which can lead to unexpected overrides and bugs that can be very detrimental to project maintenance. This is for study only.
Function.prototype.bind = function(context, ... PreArgs) {// Note that the arrow function has no scope, its scope is the parent scopereturn(... Args) => {// this => callbindThe function ofreturnthis.call(context, ... preArgs, ... args) } }Copy the code
So, the button event binding above could also say:
Btn.addeventlistener (btn.addeventListener ('click', print.bind(context))
Copy the code
Now that we’ve implemented bind, how about five lines?
conclusion
As you can see from the example of curryification, bind is actually a function curryification. By customizing scope and parameters for the objective function, the humanization requirement is met in the development process. So bind isn’t as hard as you think, is it?
In addition, functions can be currified or anti-Currified. Inverse Corrification can be used to separate functions from prototypes to facilitate function calls:
let push = Array.push.uncurry()
let obj = {}
push(obj, 1, 2)
console.log(obj) // { '0': 1, '1': 2, length: 2 }
Copy the code
Amazing, isn’t it? There are plenty of articles on the nuggets to explore for yourself.
other
If you have any mistakes or suggestions, welcome to the comments section, I will humbly adopt, wish you a smooth interview!