this

The This mechanism is specific to JavaScript and addresses the need to use properties inside objects in methods inside objects.

Instead of using this to implement properties inside objects, JavaScript can use objects. Property access to:

let people = {
	name: 'litangmm'.logName: function(){
        console.log(people.name)
    }
}
Copy the code

This approach, the method is strongly coupled to the object. When an object variable changes, the method must change. If you have an anonymous array of objects, then the position of the object changes and the method changes.

let peoples = [
    {name:'litangmm'.logName: function(){console.log(peoples[0].name)}},
    {name:'litangmm1'.logName: function(){console.log(peoples[1].name)}},
    {name:'litangmm2'.logName: function(){console.log(peoples[2].name)}},
]
Copy the code

So, this appears.

This is bound to the execution context. This is determined at runtime.

  1. In the global context, this refers to the global window.
  2. When executed as a function, it points to the object itself if it is executed as a function of an object, otherwise it points to the global window.
  3. 1 and 2 are in non-strict mode, so in global mode, this doesn’t get the global windowundefined.

And bind apply call new, which is closely related to this.

Bind apply call are all prototype methods of a function that can change the direction of this that the function executes. They all work like this:

When executed as a function, if executed as a function of an object, it refers to the object itself.

It’s just different in some details. Below, understand the similarities and differences by writing their implementations by hand.

Call and apply

perform

  1. Change thisarg
  2. Receive function input parameter
  3. Executive function

instructions

  1. For thisarg, in non-strict mode, if thisarg is null or undefined, thisarg will be a global window.
  2. For function inputs, call receives multiple parameter values, and apply receives a list of parameters.
// mycall.js
Function.prototype.mycall = function(thisarg,... args){
    let context = thisarg || window
    context.fn = this 
    constres = context.fn(... args)delete context.fn
    return res
}
function logNameAndAge(age, sex){
    console.log(this.name,age,sex)
}
logNameAndAge.mycall({name:"litangmm"},21.'man') // litangmm 21 man
Copy the code

Context. fn = this One thing we’re doing here is defining a property fn on the context and assigning it to this. **this is the function A that calls myCall. ** Thus, on the next line, function A is called as an object function of the context object, and function A executes this that naturally refers to the context.

Of course, there is room for improvement in this code:

  1. Check whether this is a function.
  2. Thisarg if thisarg is passed with fn property, this property will be overridden.

Let’s consider these cases and implement Apply.

// myapply.js
Function.prototype.myapply = function(thisarg,args){
    if(typeof this! = ='function') {throw new TypeError('error')}let context = thisarg || window
    const fn = Symbol()
    context.fn = this 
    constres = context.fn(... args)delete context.fn
    return res
}
function logNameAndAge(age, sex){
    console.log(this.name,age,sex)
}
logNameAndAge.myapply({name:"litangmm"},21.'man'])  // litangmm 21 man
Copy the code

Description:

  1. throughtypeofDetermines whether a function is called.
  2. throughSymbolTo resolve attribute conflicts.

bind

perform

  1. Change thisarg.
  2. Receive function input parameter.
  3. Return function.

For the return function

  1. Can be connected to the income.
  2. Can be used as a constructor.
  3. Bind is bound when used as a constructorthisWill be ignored.

bindThe difficulty of implementation is

  1. bindA call can accept arguments at execution time (similar to a call that accepts multiple arguments), and a returned function can also accept arguments.
  2. Determine whether the return function is used as a constructor.
// mybind.js
Function.prototype.mybind = function(thisarg,... args1){
    if(typeof this! = ='function') {throw new TypeError('error');
    }
	const that = this;
    let fBound = function(. args2){
        return that.apply(this instanceof fBound ? this: thisarg,args1.concat(args2));
    }
    let fNop = function(){};
    fNop.prototype = that.prototype;
    fBound.prototype = new fNop();  
    return fBound;
}
Copy the code

Bind is essentially a function decorator:

  1. Parameter splicing.
  2. For a normal call, use bind’s this.
  3. When a return function is used as a constructor, this of the return function is used.

instructions

This instanceof F is used as a constructor. This instanceof F is used as a constructor.

  1. Create an empty object.

  2. Specifies the empty object’s __proto__ as the constructor’s prototype.

  3. Bind the empty object to the constructor.

  4. Execute the bound constructor.

  5. If the constructor has a return value, it returns the return value, otherwise it returns an object.

! Note step 2, because the constructor returned is fBound, and we want to get a prototype on that, so we have code

fBound.prototype = that.prototype;	
Copy the code

Prototype === that. Prototype === the address of the prototype object, so operating on fbound. prototype changes that. So, we can use prototype chains to connect fBound to that.

let fNop = function(){};
fNop.prototype = that.prototype;
fBound.prototype = new fNop();   
Copy the code

Prototype is an object whose __proto__ points to that. Prototype. Refer to this article.

! Note that in steps 3 and 4, when the constructor executes, the empty object’s __proto__ already points to the constructor’s prototype. So, the this of the bound constructor can be found in the prototype chain.