call/apply/bind method/function native implementation of JavaScript

Keywords: Javascript Windows

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;
    };
}

Posted by andygrant on Thu, 10 Oct 2019 05:15:46 -0700