js function this understanding? Handwritten apply, call, bind is enough

First, what is this?

This refers to the environment object on which the function is executed. That is to say, this of the function points to the execution environment of the calling function.

function a(){
    return  this
}
console.log( a() === window) //true

The function's this keyword behaves slightly differently in JavaScript, and there are also some differences between strict and non-strict modes.

function a(){
    'use strict'
    return  this
}
console.log( a() === undefined) //true

2. Where does this point to?

this is the key word of the function and points to the calling object of the function.

The general direction can be summarized as follows:

1. When a function is called as a global environment

var name = 'window';
function a(){
    return  this.name
}
a() ==='window' //true

2. When a function is called as an object method

var obj = {
    name:'obj',
    sayName:function(){
        return this.name
    }
}
console.log( obj.sayName() === 'obj') //true

//Make a slight change; add the following code.

var sayName = obj.sayName;
console.log( sayName() === 'obj') //false

//At this point, this in the sayName function points to window.

//It needs to be clear here that the function name is only a variable containing pointers, and the function is a complex data type, so the function name is only a pointer, pointing to the memory address in the heap! So sayName just copies the pointer address at this point, so it's clear that the code above is rewritten to the following.

var sayName = function(){
    return this.name
}
var obj = {
    name:'obj',
    sayName:sayName
}
console.log( obj.sayName() === 'obj') //true
console.log( sayName() === 'obj') //false

3. When a function is called as a dom node event

var container3 = document.getElementById('container3')
container3.onclick = function(){ //Point to the node itself
    console.log(this) //<div id="container3">container3</div>
}

4. As a constructor strength method

function A(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name)//Point to instance object
    }
}
var a = new A('aa');
a.sayName(); //aa

5. this in the arrow function

var name = 'window'
var obj = {
    name:'obj',
    fn:function(){    
       (function (){
        console.log(this.name)
       })()
    }    

}
obj.fn() //window

//Ordinary functions, because closure functions are executed by windows, this points to windows.
//this of the arrow function points to the scope at which the function was created.

var name = 'window'
var obj = {
    name:'obj',
    fn:function(){    
       (()=>{ //Change to arrow function
        console.log(this.name)
       })()
    }    

}
obj.fn()

//Change to the arrow function, and you can see that the scope of creation is the scope of obj.fn function execution, that is, obj.

3. How to change the direction of this

js provides some ways to change the scope of function execution. Because if a normal function changes the context of this execution by the above writing, the writing is too cumbersome.

Application, call, bind usage

apply:
fn.apply(thisObj, array parameter)
Definition: Applying one method of an object to replace the current object with another
Note: If the parameter is not of array type, a TypeError error is reported.

call:
fn.call(thisObj, arg1, arg2, argN)
The only difference between apply and call is the format of the received parameters.

bind:
fn.bind(thisObj, arg1, arg2, argN)
The bind() method creates a new function. When the bind() is called, this of the new function is specified by the first parameter of the bind, and the rest of the parameters are used as parameters of the new function.

Implementation of apply, call and bind

apply Realization:

Function.prototype.myApply= function(context){
    context.fn = this;//1. Mount the function to the incoming object
    var arg = [...arguments].splice(1)[0];//2. Taking parameters
    if(!Array.isArray(arg)) {
        throw new Error('apply The second parameter must be an array') //3. Restrict parameter types to arrays
    }    
    context.fn(arg) //4. Method of executing objects
    delete context.fn; //5. Method of removing objects
}

var obj = {
    name:'obj'
}
function sayName(arr){
    console.log(this.name,arr)
}
sayName.myApply(obj,[1,2,3]) //obj [1, 2, 3]
call Achieve: apply The only difference is that the parameter formats are different.

Function.prototype.myCall= function(context){
    context.fn = this;//1. Mount the function to the incoming object
    var arg = [...arguments].splice(1);//2. Taking parameters
    context.fn(...arg) //3. Method of executing objects
    delete context.fn; //4. Method of removing objects
}
var obj = {
    name:'obj1'
}
function sayName(){
    console.log(this.name,...arguments)
}
sayName.myCall(obj,1,2,3,5) //obj1 1,2,3,5


bind stay mdn Realization on:

Function.prototype.myBind = function(oThis){
    if(typeof this !== 'function'){
        throw new TypeError('The bound object needs to be a function')
    }
    var self = this
    var args = [].slice.call(arguments, 1)
    fBound = function(){ //When this instance of fBound ==== true, it means that the returned fBound is called as a new constructor
        return self.apply(this instanceof fBound ? this : oThis, args.concat([].slice.call(arguments)))
    }
    var func = function(){}
    //Maintaining prototype relationships
    if(this.prototype){
        func.prototype = this.prototype
    }
    //Make fBound.prototype an instance of func. If the returned fBound is the constructor of new, the _proto_ of the new object is the instance of func.
    fBound.prototype = new func()
    return fBound
}

Keywords: Javascript Windows REST

Added by anf.etienne on Thu, 08 Aug 2019 16:09:17 +0300