In most common programming languages, this is the keyword (self is used in Objective-C)

In common object-oriented programming languages, such as Java, C++, Swift, Dart, and a host of others, this usually only appears in class methods.

That is, you need to have a class in which methods (especially instance methods) in which this represents the object being called

However, the value of this in JS is much more diverse and flexible

The effect of this

// Every method on this object wants to get obj.name when called
// However, if we change obj to foo, it means that we need to change the function internally, which is very inconvenient
var obj = {
  name: "klaus".running: function() {
    console.log(obj.name + " running");
  },
  eating: function() {
    console.log(obj.name + " eating");
  },
  studying: function() {
    console.log(obj.name + " studying"); }}Copy the code
// At this point we can use this instead
// this represents the caller of the current method
var obj = {
  name: "klaus".running: function() {
    console.log(this.name + " running");
  },
  eating: function() {
    console.log(this.name + " eating");
  },
  studying: function() {
    console.log(this.name + " studying"); }}Copy the code

Binding rules

By default, this refers to the current caller, so the value of this is only known at runtime

At compile time, there is no way to get the value of this

The basic rule

The default rules

Independent function calls can be understood as functions that are not bound to an object to be called

This is the default

// Independent function calls can be divided into the following three cases

// 1. Plain function calls
function foo() {
  console.log(this); // => window
}

foo();

// --------------------------------------------------

// 2. Function call chain
// 2.
function test1() {
  console.log(this); // => window
  test2();
}

function test2() {
  console.log(this); // => window
  test3()
}

function test3() {
  console.log(this); // => window
}
test1();

// --------------------------------------------------

// 3. Functions are passed as arguments
function foo(func) {
  func()
}

function bar() {
  console.log(this); // => window
}

foo(bar);
Copy the code

Implicit binding

The function is called by an object,

This is the name of the current function

// 1. Call a function from an object
function foo() {
  console.log(this); // => object obj
}

var obj = {
  name: "klaus".foo: foo
}

obj.foo();

// --------------------------------------------------

// 2. Chain calls to objects
function foo() {
  console.log(this); // => object obj
}

var obj1 = {
  name: "obj1".foo: foo
}

var obj2 = {
  name: "obj2".obj1: obj1
}

obj2.obj1.foo(); // <=> const tmp = obj2.obj1; tmp.foo();
Copy the code

According to the binding

Call and apply methods
function foo() {
  console.log(this);
}

foo.call(window); // window
foo.call({name: "klaus"}); // => {name: "klaus"}
// The first argument to call and apply is an object. If it is not an object, it is implicitly converted to an object before this is modified
// The difference between call and apply:
Call (this, param1, param2,...); // Call (this, param1, param2,...);
// Apply (this, [param1, param2,....); // Apply (this, param1, param2,....)
foo.call(123); // Number{ [[PrimitiveValue]] } 

// --------------------------------------------------

/ / the bind method
function foo() {
  console.log(this);
}

var obj = {
  name: "klaus"
}

// The bind method returns a new method in which this is modified
// This is the biggest difference from call and apply, which modify this directly and call the function immediately
// bind modifies this and returns a new function, not called immediately
var bar = foo.bind(obj);

bar(); // => object obj
Copy the code

Built-in function

setTimeout(function() { // => setTimeout, serInterval this is the window
  console.log(this); // => window
}, 1000);

// --------------------------------------------------

var names = ["abc"."cba"."nba"];
names.forEach(function(item) { // => array callback functions (forEach,filter,map...) This in is window
  console.log(this); // => window x 3
});

var names = ["abc"."cba"."nba"];
var obj = {name: "klaus"};
names.forEach(function(item) {
  console.log(this); // => obj object x 3
}, obj);  // => The array callback usually has a second argument that specifies the this value of the current callback

// --------------------------------------------------

var box = document.querySelector(".box");
box.onclick = function() { // This in the browser event is the DOM element object that triggers the event
  console.log(this); // => box object
}
Copy the code

The new keyword

/ / create a Person
function Person(name) {
  console.log(this); // => Person {}
  this.name = name; // Person {name: "klaus"}
}

1. Create a brand new object; 2. Refer this to this object 3. Execute the corresponding code in constructor 4. Return this object */
var p = new Person("klaus");
console.log(p); Person {name: "Klaus "} => Person {name:" Klaus "} =
Copy the code

Rule priority

New Binding > Show Binding > Implicit Binding > Default binding

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

var obj1 = {
  name: "obj1".foo: foo
}

var obj2 = {
  name: "obj2".foo: foo
}

Implicit binding and display binding exist at the same time, and display binding has higher priority
obj1.foo.call(obj2); // => obj2 objects
// <=> const tmp = obj1.foo; tmp.call(obj2); 
Copy the code
function foo() {
  console.log(this);
}

var obj = {
  name: "klaus".foo: foo
}

new obj.foo(); // => foo object
// <=> const tmp = obj.foo; new tmp();
Copy the code
function foo() {  console.log(this); }var obj = {  name: "obj"}// The new keyword takes precedence over the bind function var bar = foo.bind(obj); var foo = new bar(); / / / / = > foo object -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the function foo () {the console. The log (this); Var foo = new foo.call(obj); var foo = new foo.call(obj); // error
Copy the code

Exception to the rule

Ignoring to show bindings

If we pass null or undefined in the display binding, the display binding is ignored, using the default rule

function foo() {  console.log(this); }var obj = {  name: "klaus"}foo.call(obj); // => obj object foo.call(null); // => windowfoo.call(undefined); // => windowvar bar = foo.bind(null); bar(); // => window
Copy the code

Indirect function reference

function foo() {  console.log(this); }var obj1 = {  name: "obj1".foo: foo}; var obj2 = {  name: "obj2"}obj1.foo(); Num1 = num2 = 2*/(obj2.foo = obj1.foo)(); // => window (obj2.foo = obj1.foo)() <=> foo()// obj2.foo = obj1.foo => The result is the reference address of the function foo
Copy the code

Arrow function

The arrow function in ES6 does not have this inside; it determines this based on the outer scope.

// ES5var obj = { data: [], getData: function() { var _this = this; SetTimeout (function() {var res = [" ABC ", "CBA "," NBA "]; _this.data.push(... res); }, 1000); }}obj.getData(); // ------------------------------------------------// ES6var obj = { data: [], getData: Function () {setTimeout(() => {function() {setTimeout() => {function() {setTimeout() => {function() {setTimeout() => { Var res = [" ABC ", "CBA "," NBA "]; this.data.push(... res); }, 1000); }}obj.getData();
Copy the code

The interview questions

var name = "window";var person = {  name: "person".sayName: function () {    console.log(this.name);  }};function sayName() {  var sss = person.sayName;  sss(); // => window person.sayName(); // => person (person.sayName)(); // => person (b = person.sayName)(); // => window}sayName();
Copy the code
var name = 'window'var person1 = {  name: 'person1'.foo1: function () {    console.log(this.name)  },  foo2: () = > console.log(this.name),  foo3: function () {    return function () {      console.log(this.name)    }  },  foo4: function () {    return () = > {      console.log(this.name)    }  }}var person2 = { name: 'person2' }person1.foo1(); // => person1person1.foo1.call(person2); // => person2person1.foo2(); // => windowperson1.foo2.call(person2); // => windowperson1.foo3()(); // => windowperson1.foo3.call(person2)(); // => windowperson1.foo3().call(person2); // => person2/* var person1 = { name: 'person1', foo4: function () { // 2. Go one level above the arrow function, in person1.foo4(), Return () => {// 1.person1.foo4 ()() => There is no this console.log(this.name)}}}*/person1.foo4()(); // => person1person1.foo4.call(person2)(); // => person2person1.foo4().call(person2); // => person1
Copy the code
var name = 'window'function Person (name) {  this.name = name  this.obj = {    name: 'obj'.foo1: function () {      return function () {        console.log(this.name)      }    },    foo2: function () {      return () = > {        console.log(this.name)      }    }  }}var person1 = new Person('person1')person1.obj.foo2()() Obj object // person1.obj.foo2() returns the arrow function, so the upper level is the person1.obj.foo2 method, in which case this is person1.obj
Copy the code