To determine this

It can be judged in the following order:

  • Is the function innewIn the call? If it isthisThe binding is to the newly created object.
  • Whether the function passesCall (), appl(), or bind()The binding? If it isthisBinds to the specified object.
  • Is the function called in a context object? If it isthisThe binding is that context object.
  • If none of the above rules are met, use the default binding. If in strict mode, bind toundefinedOtherwise, bind to the global object.

The position

Before you understand the this binding process, understand the call location: The call location is where the function is called in the code (not where it is declared). Each function’s this is bound at call time, depending entirely on where the function is called (that is, how the function is called).

function baz(){
  // Current call stack: baz
  console.log("baz");
  bar();   // Where bar is called
}
function bar(){
  // Current call stack: baz -- bar
  console.log("bar");
  foo();  // Foo's call location
}
function foo(){
  // Current call stack: baz -- bar -- foo
  console.log("foo");
}
baz();   // Call location of baz
Copy the code

Binding rules

1. Bind the new keyword

In JavaScript, including built-in object functions (such as Number(…)) , Array (…). ) can be called with the new operator. Such function calls are called constructor calls. There really is no such thing as a “constructor”, only a “constructor call” to a function.

When a function is called using new, or when a constructor call occurs, the following action is automatically performed:

  • 1. Create a new object in memory.
  • 2. The new object will be [[prototype]] concatenated, meaning that the __proto__ property inside the new object will be assigned to the prototype property of the “constructor”.
  • 3. This inside the “constructor” is assigned to this object (this refers to the new object).
  • 4. If “constructor” returns a non-empty object, return that object; Otherwise, the newly created object is returned.
function createNew(base,... args){
  var obj = {};
  obj.__proto__ = base.prototype;
  let res = base.apply(obj, args);
  return res instanceof Object ? res : obj;
}
function Person(name) {
  this.name = name;
}
Person.prototype.sayName = function () {
  console.log(this.name)
}
const p = createNew(Person,'jackson');
console.log(p.name) // jackson
p.sayName();      // jackson
Copy the code

This is what happens when a function is called through new. To bind this to a function using the new keyword, consider the following code:

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function(){
    console.log(this.name); }}let person1 = new Person("bob".20."Student");
let person2 = new Person("Jack".36."Doctor");

person1.sayName();         //bob
console.log(person1.age);  / / 20
person2.sayName();         //Jack
console.log(person2.job);  //Doctor
Copy the code

New is a method that affects the behavior of the this binding when a function is called. Use new to call Person(…) We create a new object and bind it to Person(…) Call to this.

2. Bind call(), apply(), or bind()

Call (), the apply ()

var a = 11;
function foo(){
  console.log(this.a);
}
const obj = {
  a: 28
}
foo();         //11, this points to window
foo.call(obj); // this points to obj
Copy the code

Through the foo. Call (…). , we can force foo to bind its this to obj when calling foo. Call () and apply() take an object as their first argument, bind it to this, and then specify this when the function is called.

fun.call(obj, arg1, arg2, arg3,...) ;// The second argument to call is the elements in the array, listed one by onefun.apply(obj, [arg1, arg2, arg3,...] );// The second argument to apply is an array of parameters

Copy the code

bind()

Bind returns a new function that sets the argument to the context of this and calls the original function.

function foo(num) {
  console.log(this.a, num);
  return this.a + num;
}
const obj = {
  a: 11
};
const bar = foo.bind(obj);
const b = bar(28);    / / November 28
console.log(b);       / / 39
Copy the code

3. Implicit binding

You need to consider whether the function is called in a context object, and if so, this is bound to that context object.

function foo() {
  console.log(this.a);
}
const obj1 = {
  a: 11.foo: foo
}
const obj2 = {
  a :28.foo: foo
}
obj1.foo();   // This is bound to obj1 when 11 calls foo()
obj2.foo();   // this is bound to obj2 when foo() is called
Copy the code

In the code above, the function foo is added to an obj object as a reference property, and when foo is called, its landing point is the OBj object. When a function reference has a context object, the implicit binding rule binds this in the function call to that context object.

4. Default binding

The most common type of function call is the stand-alone function call, and you can think of this rule as the default rule when no other rule applies. See how Foo is called by analyzing where it is called. In the following code, foo() is called directly with an undecorated function reference, so it is the default binding and no other rules can be applied.

window.a = 11;
function foo(){
  console.log(this.a);
}
foo();  // when 11 calls foo, this.a is resolved to a global variable, and the default binding for this points to a global object
Copy the code
window.value = 1;
function foo() {
  console.log(value);  / / 1
}
function bar() {
  let value = 2;
  foo();
  // console.log(value); / / 2
}
bar();
Copy the code

Note: If you use strict mode (“use strict”), the default binding will not be available for global objects and an error will be reported.

Bind the exception

  • If you putnullorundefinedAs athisThe binding object is passed incall(),apply()orbind(), these values are ignored when called, and the default binding rules are actually applied.
  • Arrow functions do not use the above rules, but are determined by the outer (function, global, or block) scopethisAnd cannot be modified after binding. Arrow functions don’t have their ownthisPointer, which is not generated under its own scope when calledthisIt inherits only from the upper layer of its scope chainthis.
window.name = 11;
var obj = {
    name: 28.say: function(){
        const foo = () = > {
            return this.name;
        }
        console.log(foo()); // 28 // The direct caller is window, but since the arrow function does not bind this, this is obj object in the context
        const bar = function(){
            return this.name;
        }
        console.log(bar()); // 11// The direct caller is the window normal function, so
        return this.name; }}console.log(obj.say()); // this is the obj object in the context of the function in which the direct caller is executing
Copy the code