It’s a cliche, nothing special. Keep the following notes for yourself and share them with those who haven’t made a summary yet

Several common scenarios

This in JavaScript represents the environment object in which the code is currently executing. The general distinction is what environment object this refers to when it appears in a function. The main scenarios are as follows:

  • The function is called as a property of an object => whoever calls it
  • Call the function directly => whoever the global is
  • Function call scenarios for Call, apply, and bind => bind is whoever you bind
  • The constructor call to the function => newly created object

Object property call

Everything can be a property of an object, and this refers to the object if the function is called as an object property.

var obj = {
    name: 'six strange'.getName:function() {
        console.log(this.name)
        console.log(this === obj)
    }
}

obj.getName() True / / 6
Copy the code

The getName function is called as a property of the obj object, where this inside the function refers to the object obj on which the function was called

Ordinary function calls

Execute a defined function directly, as if it were executed in the global environment, with this pointing to the window


var obj = {
    name: 'six strange'.getName:function() {
        console.log(this.name)
    }
}
name = 'global'
var globalGetName = obj.getName
globalGetName() // global
Copy the code

The getName function is defined inside the obj object, but refers to obj. GetName with its new alias globalGetName, and then calls globalGetName like a normal function when this refers to the global object instead of the obJ object. Here involves some memory data structure management problems, details can go to see javascript this principle – Ruan Yifeng

Also consider the following code: inside the bound onClick event, the first this points to the object that is currently firing the event, and the event is fired as a property of the object. But the second this is executed inside an internally defined function, which is a normal call to the function, so this refers to a global object and has no id defined so it is undefined

// https://jsbin.com/bacixul/1/edit?html,console,output
<div id="app">click me !</div> 
<script>
document.getElementById('app').onclick = function() {
        console.log(this.id)// app
        var myalert = function() {
          console.log(this.id) // undefined
        }
        myalert()
}
</script>
Copy the code

The obvious solution to these scenarios is to save this in an intermediate variable.

//https://jsbin.com/tuvefus/edit?html,console,output  
<div id="app">click me !</div> 
  <script>
    document.getElementById('app').onclick = function() {
      var that = this // Save this point
      console.log(this.id)// app
      var myalert = function() {
        console.log(that.id) // Use that instead of this after the app
      }
      myalert()
}
  </script>
Copy the code

You can also use the arrow function in ES6 to get around this problem

  <div id="app">click me !</div> 
  <script>
    document.getElementById('app').onclick = function() {
      console.log(this.id)// app
      var myalert = (a)= > { // Use the arrow function
        console.log(this.id) // app 
      }
      myalert()
}
  </script>
Copy the code

call & apply & bind

All three of these apis are used to modify the this reference of function execution. Call and apply return the result of the function, and bind returns the function after this is pointed to.

Call and Apply simulate the implementation

The implementation of these two functions is almost the same, except that the way arguments are passed is different. Call is the sequence of incoming parameters, and apply is the list of incoming parameters.

// call
Function.prototype.myCall = function (context) {
    // Get the object to bind
    var context = context || window
    // Add a property to the context to call the function
    context.fn = this
    // Take out the parameters after the context
    var args = [...arguments].slice(1)
    // Execute the function
    varresult = context.fn(... args)/ / delete the fn
    delete context.fn
    return result
  }
// apply
Function.prototype.myApply = function (context) {
  var context = context || window
  context.fn = this
  var result
  // Need to determine whether to store the second parameter
  // If it exists, expand the second argument. The second argument is the argument array. The element is the argument list when the function is called
  if (arguments[1]) { result = context.fn(... arguments[1])}else {
    result = context.fn()
  }

  delete context.fn
  return result
}
Copy the code

It can be seen that the implementation idea of Call and apply is to add the function to be executed as an attribute to the target object, and delete the attribute after execution, so that the execution of the function becomes the attribute call of the object, and this refers to the target object.

Bind simulation implementation

The implementation of bind can rely on either call or apply

Function.prototype.mybind = function(context) {
  var self = this // save the original function
  return function(){ // returns a new function that binds the context
    return self.apply(context, arguments) // New functions can be treated as apply or call}}Copy the code

React binds this to method calls, such as onClick={this.handleclick.bind (this)}.

A constructor call to a function

The reference to this in a function construction call is really the process of understanding new. New is a constructor call that binds this to the new object generated by new. The new operator uses the following procedure:

  • Create a brand new object
  • This object will be executed[[Prototype]]The connection
  • This object is bound to the function callthis
  • If the function returns no other object, thennewThe function call in the expression automatically returns the new object
var mynew = function() {
    // 1 Creates a new object
    var obj = Object.create(null)
    // 2 Gets the function that needs to be constructed
    var fn = [].shift.call(arguments)
    // 3 prototype link
    // obj.__proto__ = fn.prototype
    obj = Object.setPrototypeOf(obj,fn.prototype)
    // 4 Bind this to execute the constructor
    var res = fn.apply(obj, arguments)
    // 5 Returns the generated object
    return typeof res === 'object' ? res : obj
}
Copy the code