This is basic in javaScript and easy to understand. Some people always don’t know when this is called and where it points to. In this article, we will sort out all the situations in which this occurs, classify and summarize, and take some interview questions to have a look. There are two precursors (the arrow function features, and how the new modifier works) that I saved for last, but you can look at them first. Let’s get down to business:

What is this

This is the keyword inside the object. Before the arrow function, the pointer to this was generated at the time of the call, or it could be said that whoever called pointed to the object. This could be used to access the attributes in the pointing object. Let’s talk about how this can be bound:

  1. The default binding
  2. Implicit binding
  3. According to the binding
  4. Mandatory binding
  5. newInstantiate the binding

The default binding

When there are no binding rules, the default binding is used. It’s also fairly common.

var a = 1;
function fn(){
    console.log(this.a);
}
fn() / / 1
Copy the code

By default, this refers to the object on which fn is called, and when fn is executed, the window is called. We can talk about GO initialization in JS scripts and AO and precompilation running in the call stack, and see why we call window. 1. If we declare a variable with let const, we cannot access it with this because it is not hanging on the window. 2. When using strict mode, this is undefined.

function fn(){
    "use strict"
    console.log(this);
}
fn() // undefined
Copy the code

Implicit binding

If the function is called on an object, this refers to that object.

var a = 2;
var obj = { 
    a: 3,
    foo() { 
        console.log( this.a );
    }
};

obj.foo(); // 3
Copy the code

When the foo method is called with obj, foo’s call is in the context of obj,this is implicitly bound to obj, and this.a is 3. What about nested, multi-layer calls?

function foo() { console.log( this.a ); } var a = 2; var obj1 = { a: 4, foo: foo }; var obj2 = { a: 3, obj1: obj1 }; obj2.obj1.foo(); / / 4Copy the code

Obj1. obj1 calls obj1=>obj1.foo calls foo,foo executes, this still points to the final object called obj.

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

var a = 2;

var obj1 = { 
    a: 4,
    foo: fn
};


let bar = obj1.foo(); 
bar() //2
Copy the code

But pay attention to the assignment process, since fn is assigning to obj.foo by reference. The memory address points to the same place, so it’s similar to calling bar with window when this.a is 2.

According to the binding

Call () and apply(); call() and apply() have different internal arguments. Call () and apply() have different internal arguments. Call (), apply(), and bind() can be covered in an article. There are also many related articles on the Internet, without explanation

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

var a = 2;

var obj1 = { 
    a: 3};var obj2 = { 
    a: 4}; foo.call( obj1 );/ / 3
foo.call( obj2 ); / / 4
Copy the code

Foo is placed in obj1, and obj1 calls foo, in which case this points to obj.

Mandatory binding

If a function developer does not want other people to change this, it can also wrap another layer of functions and call it.

function foo() { console.log( this.a ); } var a = 2; var obj1 = { a: 3, }; var obj2 = { a: 4, }; var bar = function(){ foo.call( obj1 ); } bar.call( obj2 ); / / 3Copy the code

Bar () already refers this to the context of obj2, but the inner function is bound to the context of obj1, so the output is still 3.

New instantiates the binding

The new modifier eventually generates an object that points this in the function to the new object, independent of global variables.

function Foo(a) { 
    this.a = a;
}

var a = 2;

var bar = new Foo(3);
console.log(bar.a); / / 3
Copy the code

But if the function has a return value, then this points to the return value of the function.

function Foo(a) { 
    this.a = a;
    return {
        b:a
    }
}

var a = 2;

var bar = new Foo(3);
console.log(bar.a); // undefined
console.log(bar.b); / / 3
Copy the code

The above binding modes have ascending priorities:

  1. Call (new binding) in new? If so, this binds to the newly created object.
  2. Is it called through Call, apply(explicit binding), or hard binding? If so,this binds to the specified object.
  3. Is it called in a context object (implicit binding)? If so,this binds to that context object.
  4. If neither, use the default binding. If in strict mode, it is bound to undefined, otherwise it is bound to global objects.

Pre-knowledge:

  1. Arrow function features.
  2. newHow modifiers work.

This is a brief introduction. That’s not the topic, after all.

Arrow function characteristics

The difference between arrow functions and normal functions:

  1. Writing method to simplify return.
  2. Cannot be used as a constructor and cannot be usednew. Because the arrow function doesn’tptototype
  3. Arrow function doesn’t have anyargumentsCan be received with the REST parameter.
  4. Arrow functions are not boundthisInstead, it captures this from the context as this inside the function.
  5. The arrow function goes throughcall() apply()Method calls a function with only one argument. This is not affected.
  6. Arrow functions should not be treated as Generator functions and the yield keyword should not be used.

// Simplify return
let fn = (value) = > {
    return value
}
/ / equivalent to the
let fn = (value) = > value

// we can't use new
let FunConstructor = () = > {
    console.log('lll');
}
let fc = new FunConstructor(); / / Uncaught TpyeError error

Copy the code

newHow modifiers work

The new keyword actually performs the following steps when calling the constructor:

  1. Create a new object
  2. Assigns the constructor’s scope to the new object (so this refers to the new object)
  3. Execute the code in the constructor (add attributes to this new object)
  4. Return a new object
// A simple new implementation
function myNew() { 
    const obj = {},
        Constructor = [].shift.call(arguments) 
    obj.__proto__ = Constructor.prototype
    const res = Constructor.apply(obj, arguments); 
    return typeof res === 'object' ? res : obj; 
}
Copy the code

Internally creates an empty object, assigning the constructor’s prototype value to the new object’s __proto__ and this to the newly created object. If the constructor returns a non-empty object, that object is returned; otherwise, the object created in the first step is returned.