Brief introduction of call/apply/bind method
In JavaScript, the direction of this in a function is usually determined only when it is called, and JavaScript provides a call/apply/bind method that allows us to display the direction of this in a bound function.
Their first parameter is an object, which they bind to this in the function that calls them. Because you can specify this binding object directly, we call it explicit binding.
//Use cases var a = { q: 1 }; var b = { q: 2 }; var c = { q: 3 }; function cs(s) { console.log(this.q) } cs.bind(a)();//1 cs.call(b);//2 cs.apply(c);//3
tips
var s = new fn.myBind({ a: 2333 })();//Report errors!! Operational priority: property access > parameterized new > function call > parameterized new var s = new (fn.myBind({ a: 2333 }))();//Correct posture
Implementation of Custom Call Method
The parameter starts with arguments[1], func.myCall(obj:Object[,agr1: any[,agr2:any [...]])
if (!Function.prototype.myCall) { Function.prototype.myCall = function (targetThis) { //targetThis defaults to windows (strict mode is not allowed) targetThis = targetThis || window; //Specify this using object calls targetThis.fn = this; //Collect parameters var agrs = []; //Because arguments [0]==== targetThis, start with subscript 1 for (var ge = 1, len = arguments.length; ge < len; ge++) { agrs.push('arguments[' + ge + ']'); } //Expansion of parameters and execution of functions using eval var result = eval('targetThis.fn(' + agrs + ')'); //Delete attributes of additional objects to eliminate side effects delete targetThis.fn; //Return results return result; } }
Implementation of Custom apply Method
Parameters are placed in an array of func.call(obj:Object[,agr:Array])
if (!Function.prototype.myApply) { Function.prototype.myApply = function (targetThis, arrAgrs) { //targetThis defaults to windows (strict mode is not allowed) targetThis = targetThis || window; //Specify this using object calls targetThis.fn = this; var agrs = []; //Collecting Array of Parameters for (var ge = 0, len = arrAgrs.length; ge < len; ge++) { agrs.push('arrAgrs[' + ge + ']'); } //Expansion of parameters and execution of functions using eval var result = eval(' targetThis.fn(' + agrs + ')'); //Delete attributes of additional objects to eliminate side effects delete targetThis.fn; //Return results return result; } }
Implementation of custom bind method
The parameter starts with arguments[1], func.myCall(obj:Object[,agr1: any[,agr2:any [...]])
//Consider parameter merging and new priority and prototype inheritance if (!Function.prototype.myBind) { Function.prototype.myBind = function (targetThis) { //If this method is not called by a function object, an exception is reported. if (typeof this !== "function") { throw new TypeError( "Function.prototype.bind error" ); } //Collect parameters var bindArgs = Array.prototype.slice.call(arguments, 1), originFunction = this,//Save the original this (original function) fnProto = function () { },//Using empty function to link prototype indirectly to cope with prototype inheritance in new fnBounding = function () { //Check new Operation this Binding Priority return originFunction.apply( ( this instanceof fnProto ? this : targetThis ), bindArgs.concat( Array.prototype.slice.call(arguments) ) ) }; fnProto.prototype = this.prototype;//Link prototype //new fnProto implements a concise inheritance prototype to prevent the operation of fnBounding.prototype from polluting the originFunction prototype fnBounding.prototype = new fnProto(); return fnBounding; }; }
Soft binding
You can bind or call/apply after bind
if (!Function.prototype.softBind) { Function.prototype.softBind = function (obj) { var fn = this; // Capture all curried parameters var curried = [].slice.call(arguments, 1); var bound = function () { return fn.apply( (!this || this === (window || global)) ? obj : this, curried.concat.apply(curried, arguments) ); }; bound.prototype = Object.create(fn.prototype);//Link prototype return bound; }; }