• Why do interviewers always ask you to implement a bind function?
  • What does he want to know from Bind?
  • What’s in a little bind?

Bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind

👍 read useful students remember to point a praise to go again, your encouragement – MY great power to see what can be learned

  • To realize the bind
  • The new principle of

The narrative steps of this article

  • Bind function
  • Simulate the essentials of BIND
  • Implementation approach
  • New function special case (this& Parent prototype)

————- Manual dividing line ————-

The bind function

Returns a function to which this refers.

Simulate the essentials of BIND

  • Change the direction of this
  • Returns the function

Implementation approach

Create a function to return and change the pointer internally with call/apply, whose call/apply arguments are taken from arguments.

The implementation code is as follows:

  Function.prototype.myBind = function () {
        let exeFunc = this;
        let beThis = arguments[0];
        let args = [].slice.call(arguments ,1);
        return function () { exeFunc.apply(beThis,args); }}Copy the code

Let’s put this to the test:

	let other = {
        name: 'other'
    }
	let obj = {
        name: 'obj'.getName : function (age,height) {
            console.log(this.name);
            console.log('age' + age);
            console.log('height' + height);
        }
    }
    obj.getName.myBind(other, 14.200) ();Copy the code

The test results are normal. It prints other

Pretty easy, huh? But it’s often more than that. Then look at:

function Person() {
        this.name = 'person';
        this.getName = function (age, height) {
            console.log(this.name);
            console.log('age:' + age, 'height:'+ height); }}Copy the code

At this time:

let PersonMyBind = Person.myBind(window);
let per3 = new PersonMyBind();
per3.getName();
Copy the code

Do you print person?

Answer: Actually per3 is an empty object.

New function special case -this

So why did it go wrong. This brings us to new knowledge: if you don’t understand it, take a look at this article. This is a simulation of new code

function New (constructFunc) {
	// Let obj = New(obj); => obj = res
	var res = {};
	if(constructFunc.prototype ! = =null) {
		// Point the prototype of the instance to the prototype of the constructor
		res.__proto__ = constructFunc.prototype;
	}
	// focus ret is the result of the constructor execution, change this of the constructor to execute res
	var ret = constructFunc.apply(res, Array.prototype.slice.call(arguments.1));
	// If the constructor returns a value, it returns it directly
	if((typeof rest === "object" || typeof ret === "function") && ret ! = =null) {
		return ret;
	}
	// Otherwise return the instance
	return res;
} 
Copy the code

Bind (name, getName) == == == == == == ==

var ret = constructFunc.apply(res, Array.prototype.slice.call(arguments.1));
Copy the code

Function () {exefunc.apply (beThis,args); exefunc.apply (beThis,args); }, let me make it clear.So when this line of code executes:

var ret = constructFunc.apply(res, Array.prototype.slice.call(arguments.1));
Copy the code

To see the difference between new Person and new PersonMyBind()How can we solve this problem once we know the cause of this phenomenon? It’s actually quite simple, if it’s new:

	let resultFunc = function () {
            exeFn.apply(this, args) // We pass in this object, which corresponds to the res in the new procedure
        }
Copy the code

So the question is how to distinguish between new Person () and Person ()! The answer lies in the implementation of new. We can find this line in the new simulation above:

	// Point the prototype of the instance to the prototype of the constructor
	res.__proto__ = constructFunc.prototype;
Copy the code

That is to say executing

	let resultFunc = function () {
			// this__proto__ equals person.prototype
            exeFn.apply(this, args)
        }
Copy the code

This.__proto__ equals Person.prototype, so it’s ok to use this. Update our myBind

 Function.prototype.myBind = function () {
        if(typeof this! = ='function') {
            throw new Error('Caller must be function type');
        }
        let exeFn = this; // this is the function to be executed
        let currentThis = arguments[0]; // This to be specified
        let args = [].slice.call(arguments.1); // The rest is passed as arguments
        let resultFunc = function () {
           // Distinguish between new calls and normal calls
            exeFn.apply(this.__proto__=== resultFunc.prototype ? this : currentThis, args)
        }
        return resultFunc;
    }
Copy the code

New function special case – parent prototype

This is not the end of the story, we also need to solve the case of the Person has a parent prototype, after knowing the above knowledge is very easy to solve this problem.

    Function.prototype.myBind = function () {
        if(typeof this! = ='function') {
            throw new Error('Caller must be function type');
        }
        let exeFn = this; // this is the function to be executed
        let currentThis = arguments[0]; // This to be specified
        let args = [].slice.call(arguments.1); // The rest is passed as arguments
        let resultFunc = function () {
            // Distinguish between new calls and normal calls
            exeFn.apply(this.__proto__=== resultFunc.prototype ? this : currentThis, args)
        }
        // Maintain the parent of the original function
        if (this.prototype) {
            resultFunc.prototype = this.prototype;
        }
        return resultFunc;
    }
Copy the code

Finished work