Why this

Using this gives us the flexibility to use functions repeatedly in different contexts without having to write different versions of functions for each object.

So it’s extra important for us to know where this is pointing.

What is context?

When a function is called, an activity record is created, including where the function was called, how it was called, and the parameters passed in. This is one of the properties that is used during the function’s execution.

Misunderstanding of this

  • This refers to the function itself, okay? No!
  • This points to the function scope? No!

The this pointer is bound at run time and has nothing to do with where the function is declared, depending on how the function is called and where it is called.

## Where the function is called

First we want to understand the call location and the call stack, so here’s a function.

function baz({
  // The call stack is baz
  // Call location: global scope
  console.log('baz');
  bar();
}

function bar({
  // Call stack baz -> bar
  // Call location: baz
  console.log('bar');
  foo();
}

function foo({
  // Call stack baz -> bar -> foo
  // Call location: bar
  debugger
  console.log('foo')
}

baz()
Copy the code

Let’s execute it in the browser:

The binding rule for this

The default binding

This refers to a global object and is bound to undefined when strict mode is used within a function.

One detail: What determines whether the this binding object is in strict mode is not the call location, but whether the function body is in strict mode. See the code below:

function foo(){
    "use strict";
    console.log(this.a);
}

function foo1(){
    console.log(this.a);
}

var a = 2;
foo(); // TypeError:this is undefined


(function(){
    "use strict";
    foo1(); / / 2}) ();Copy the code

Implicit binding

Determines whether the call location has a context object or is referenced by an object that owns or contains the function. If so, this is implicitly bound to that object.

  • The this in the function only refers to the one level above it

    function foo(){
       console.log(this.a);   
    }
    var obj2 = {
        a:3.foo:foo
    };
    var obj1 = {
        a:2;
        obj2:obj2
    };
    obj1.obj2.foo() // 3 instead of 2implicitCopy the code
  • Implicit loss

    In the following example, fn is a reference to obj.foo, but it actually refers to foo itself, so fn() can be an undecorated function call with the default binding applied.

    Note: Either you define a function directly in Object or you want to define a function and add it as a reference property, the function is not strictly part of the Object.

    function foo(){
       console.log(this.a);   
    }
    var obj = {
        a:3.foo:foo
    };
    
    var a = 2;
    var fn = obj.foo;
    fn(); // 2 instead of 3
    Copy the code

Explicitly bound

Specify the binding object for this directly

  • call(thisArg,arg1,arg2,…) With the apply (…).

    • parameter

      • The binding object for this
      • The list of parameters
    • Calls a function with a specified this value and one or more arguments given separately

If a raw value is passed in, it is converted to its object form, as follows.

  • bind(thisArg,arg1,arg2,…) Hard bound –

    • parameter

      • The binding object for this
      • The list of parameters
    • Create a new function whose this is specified as the first argument to bind() when bind() is called, and the remaining arguments will be used as arguments to the new function.

  • Context of the API call

    Some apis provide optional arguments that work as well as bind(…) Also, make sure your callback uses the specified this.

    function foo(el){
        console.log(el,this.id)
    }
    var obj = {
        id:'ok'
    }
    [1.2.3].forEach(foo,obj);
    //1ok 2ok 3ok
    Copy the code

The new binding

Creation process:

  1. Create a brand new object
  2. Perform the [[Prototype]] connection
  3. Bind this object to the function call’s this
  4. If no other object is returned from the function, the created object is automatically returned.
function foo(a){
    this.a = a
}
var bar = new foo(2);
console.log(bar.a); / / 2
Copy the code

## Binding rule priority

  1. Is the function called in new? This binds to the newly created object: continue
  2. Is the function called by call, apply, or bind? The this binding specifies the object: continue
  3. Is the function called in a context object? This binds the context object: continue
  4. Default binding, is it in strict mode? Undefined: global object.

Other cases of binding

  • In Call, Apply, etc., if null is passed as a placeholder for this to be bound, the default binding rules will be applied to bind to the global object in non-strict mode, resulting in unexpected consequences, such as modifying the global object.

    • Create an empty non-delegate object and point this to it.

    Object.create(null) does not create the Object.prototype delegate, which is null than {}.

  • Indirect references (see implicit loss in implicit binding)

  • Using soft Binding

    if (!Function.prototype.softBind) {
        Function.prototype.softBind = function (obj,... args1{
            // The obj passed in is the default this binding value we want to set
            var fn = this;
            var bound = function (. args2{
                return fn.apply(
                    // If this refers to a global object, the default binding is obj
                    (!this || this= = = (window || global))? obj :this.// New argument list
                    [...args1,...args2]
                );
            };
            bound.prototype = Object.create(fn.prototype);
            return bound;
        };
    }
    // From JavaScript you don't know
    Copy the code

Arrow function this

The arrow function’s this is determined by its outer (function or global) scope. Often used in callback functions.

function foo(){
    return () = >{
        console.log(this.a)
    }
}
var obj = {
    a:2;
}
var obj2 = {
    a:3;
}
var bar = foo.bind(obj);
bar.call(obj2); // 2 instead of 3, the binding of arrow functions cannot be changed.
Copy the code