The use and implementation of bind method in Js
We have already simulated and implemented the call and apply methods before. Today, we can also change the this pointer but have a slightly different method --> bind method.
definition
First, let's look at the definition of the bind method in mdn. The bind() method creates a new function. When bind() is called, this of this new function is specified as the first parameter of bind(), and the other parameters Will be used as an argument to the new function for invocation
grammar
function.bind(thisArg[, arg1[, arg2[, ...]]])
parameter
thisArg The value passed to the target function as the this parameter when the bound function is called. This value is ignored if the bound function is constructed using the new operator. When using bind to create a function in setTimeout (provided as a callback), any primitive value passed as thisArg will be converted to object. If the parameter list of the bind function is empty, or thisArg is null or undefined, the this in the execution scope will be treated as the thisArg of the new function. hospital certificate template>.
arg1, arg2, ... Arguments that are prepended to the bound function's argument list when the target function is called.
return value
Returns a copy of the original function with the specified this value and initial parameters.
From the description in mdn above, we can see that the difference between the bind method and the call and apply methods is that the bind method also points the this of the calling function to the first parameter, but this time the function will not be executed, but a The new function is returned, except for the first parameter, the remaining parameters are passed into the new returned function for use. And the returned function can also be called by the new operator. When the new operator is used, the first this value passed in by the bind method is invalid. At this time, the function this must point to follow the this pointing principle of the new operator. ( new operator parsing).
use
function say(res, res2) { this.num = res; console.log(this); console.log(this.hello); console.log(res); console.log(res2); } let obj = { hello: 'hello' } const back = say.bind(obj, 1); back(3); // {hello: "hello", num: 1} // hello // 1 // 3
The above code can be seen from the printed value. The bind function is used to point this inside the say function to the obj object, and an attribute num is added to the obj object with a value of 1, and the parameters passed in by the back function returned by the bind function are in the bing function. Pass in after the incoming parameter. But without using the new operator, let's look at using the new operator to call the back function.
function say(res, res2) { this.num = res; console.log(this); console.log(this.hello); console.log(res); console.log(res2); } let obj = { hello: 'hello' } const back = say.bind(obj, 1); const b = new back(6); console.log(b, 'b') // say {num: 1} // undefined // 1 // 6 // say {num: 1} "b"
The above code calls the back function returned by the bind function using the new operator, and looking at the print result points the this of the say function to the strength object b generated by the new operator. Next, we will simulate and implement our own bind operator according to the rules.
Realize ideas
1. Add your own bind method to the Function prototype
2. Return a new function backFn
3. Determine whether the function is called by the new operator
4. If yes, point this to the generated strength object, if not, point this to the first value passed in
5. If the original function has a prototype object, the prototype of the returned function backFn will point to the prototype object of the original function (because the function returned by bind is equivalent to a copy of the original function)
6. Return backFn function
accomplish
// Add the bind method and pass in the parameters Function.prototype.myBind = function (thisArg, ...bindRes) { // save the function const thisFn = this; if (typeof thisFn !== 'function') { throw new TypeError(this + 'is not a function'); } const backFn = function (...backRes) { // Determine whether it is a new operator call, and if so, use the generated instance object (so the backFn function this points to the instance object, so it can directly point to this) // If the parameter is passed in, if it is an es5 implementation, you can use the arguments object // Use the apply method you wrote before to change this pointer if (new.target) { return thisFn.apply(this, [...bindRes, ...backRes]); } else { return thisFn.apply(thisArg, [...bindRes, ...backRes]); } // Or you can also write like this // return thisFn.apply(new.target? this: thisArg, [...bindRes, ...backRes]); } // Using the method of creating an empty function, point the bacnFn function prototype to the original function to prevent changing the bacnFn function prototype object and affecting the original function prototype object if (thisFn.prototype) { const emptFn = function () {}; emptFn.prototype = thisFn.prototype; backFn.prototype = new emptFn(); } return backFn; }
test
function say(res, res2) { this.num = res; console.log(this); console.log(this.hello); console.log(res); console.log(res2); } say.prototype.str = 'content' let obj = { hello: 'hello' } const back = say.myBind(obj, 1); back(3); // {hello: "hello", num: 1} // hello // 1 // 3 const b = new back(6); console.log(b.str, 'b') // backFn {num: 1} // undefined // 1 // 6 // content b
The test results are in line with the expected results, so far our own bind method has been implemented.