preface

Do not understand this this difficult, many times will cause some confusion, write some bugs DO not know how to end, so to write the bug, no, to write code together.

  • Address: this in JavaScript

  • Zhihu column: front – end attacker

  • Blog address: Damonare’s personal blog

Life must be happy, don’t make the golden bottle empty to the moon

The body of the

This in JavaScript is particularly different. For example, in the Java language, this is immutable at the execution stage of the code, whereas in JavaScript, this is bound at the invocation stage. 👌 gives this a lot of room to play because of this property. However, it is somewhat different in strict and non-strict modes, and the different ways in which functions are called also result in some differences in this. 🌹

What’s this?

😎 First, the next definition of this: this is a variable that is determined when the execution context is created that cannot be changed during execution.

The so-called execution context refers to the process in which the JavaScript engine declares some variables, functions and this used in the code before executing a piece of code and saves them in the variable object. This’ snippet ‘includes: global code (code inside script tags), code inside functions, and code inside Eval. The well-known scope chains are stored here, as an array of classes, in the corresponding function’s [[Scopes]] property.

This is determined only at the function call stage, when the execution context is created, and is stored in the variable object. This feature also contributes to the variability of this :🙂 that is, the value of this can vary depending on how a function is called.

👆👆 Above we said that this behaves differently in strict and non-strict modes:

var a = 1;
function fun() {
   'use strict';
    var a = 2;
      return this.a;
}
fun();//😨 Cannot read property 'a' of undefinedCopy the code

👆 In strict mode, this refers to undefined;

var a = 1;
function fun() {
    var a = 2;
      return this.a;
}
fun();/ / 1Copy the code

👆 In non-strict mode this points to window;

The reason why the same code behaves differently in different modes is because this behaves differently in strict and non-strict modes.

Conclusion: When a function is called independently, its this refers to undefined in strict mode, and when this refers to undefined in non-strict mode, it automatically refers to the global object (window in browser).

By the way, in the global context, this refers to itself, and look at 🌰 :

this.a = 1;
var b = 1;
c = 1;
console.log(this= = =window)//true
// All three of these can get the desired result. These three variables exist in the global context variable objectCopy the code

One more thing, what happens when this is not used in a function? See 🌰 :

var a = 1000;
var obj = {
    a: 1.b: this.a + 1
}
function fun() {
    var obj = {
          a: 1.c: this.a + 2 // Cannot read property 'a' of undefined in strict mode
    }
    return obj.c;
}
console.log(fun());/ / 1002
console.log(obj.b);/ / 1001Copy the code

In this case this still refers to the window. So we can make a separate conclusion:

When obj is declared globally, this points to the global object. When obj is declared in a function, this points to undefined in strict mode. When obj is declared in non-strict mode, this points to the global object.

👌 well, just under the test, know the difference between strict mode and non-strict mode of this, but our daily application is most often in the function with this, the above also said that this in the function of different ways to call there are differences, so what are the methods of calling the function? Four:

  • Call directly from a global environment or a normal function
  • Methods as objects
  • Use Apply and Call
  • As a constructor

Here are four cases:

Direct call

The above 🌰 is actually a direct call, but I decided to write ☝️🌰 :

var a = 1;
var obj  =  {
    a: 2.b: function () {
        function fun() {
          return this.a
        }
       console.log(fun());
    }
} 
obj.b();/ / 1Copy the code

Fun is defined in obj. B, but it is still a normal function. When called directly, it refers to undefined in non-strict mode and automatically points to a global object.

The important thing is to repeat: when a function is called independently, its this points to undefined in strict mode, and when this points to undefined in non-strict mode, it automatically points to a global object (window in browsers). 😯

Methods as objects

var a = 1;
var obj = {
  a: 2.b: function() {
    return this.a; }}console.log(obj.b())/ / 2Copy the code

The anonymous function referenced by 👆b is called as a method of obj, where this refers to the object calling it. So this is obj. What if the b method is not called as an object method? What does that mean? That’s it 👇 :

var a = 1;
var obj = {
  a: 2.b: function() {
    return this.a; }}var t = obj.b;
console.log(t());/ / 1Copy the code

The result of t is global variable 1. That is, the B property of the obj object stores a reference to the anonymous function, which can be understood as a pointer. When we assign to T, we don’t separate memory space for the new function. Instead, t stores a pointer to the function. This is equivalent to executing pseudo-code:

var a = 1;
function fun() {// This function is stored in the heap
    return this.a;
}
var obj = {
  a: 2.b: fun //b points to fun
}
var t = fun;// The variable t points to fun
console.log(t());/ / 1Copy the code

T is a pointer to fun. Calling t is equivalent to calling fun directly.

Use the apply, call

What is the use of call and apply

This is a universal formula. In fact, the code directly called above can be viewed as this:

function fun() {
      return this.a;
}
fun();/ / 1
// Strict mode
fun.call(undefined)
// Non-strict mode
fun.call(window)Copy the code

In non-strict mode, fun.call(undefined) will still print 1. In non-strict mode, fun.call(undefined) will print 1.

Why is it a universal formula? Now look at the method call of a function as an object:

var a = 1;
var obj = {
  a: 2.b: function() {
    return this.a;
  }
}
obj.b()
obj.b.call(obj)Copy the code

Do apply and call really do everything? No, the arrow function in ES6 is a special case because the arrow function’s “this” is not determined at call time, which is one of the reasons why arrow functions are useful because their “this” is fixed. We’ll talk about this for the arrow function later.

As a constructor

What is a constructor? Constructors are the functions used for new objects, such as Function, Object, Array, Date, etc., are globally defined constructors. In fact, every function can create new objects, and those functions that batch produce the objects we need are called constructors. Note that the constructor starts with a capital letter.

function Fun() {
  this.name = 'Damonre';
  this.age = 21;
  this.sex = 'man';
  this.run = function () {
    return this.name + 'Running';
  }
}
Fun.prototype = {
  contructor: Fun,
  say: function () {
    return this.name + 'Talking'; }}var f = new Fun();
f.run();//Damonare is running
f.say();//Damonare is talkingCopy the code

As shown above, if the function is used as a constructor, this represents the object it is about to new. Why? What did New do?

The pseudocode is as follows:

function Fun() {
  // New does something
  var obj = {};
  obj.__proto__ = Fun.prototype;//Base is the constructor
  obj.name = 'Damonare'; .// A series of assignments and more
  return obj
}Copy the code

That is, new does the following:

  • Create a temporary object
  • Bind prototypes to temporary objects
  • Assign a value to the corresponding property of the temporary object
  • Return temporary object

In other words, new is a syntactic sugar, and the reason this refers to a temporary object does not escape the above situations.

Of course, if you call Fun() directly, it looks like this:

function Fun() {
  this.name = 'Damonre';
  this.age = 21;
  this.sex = 'man';
  this.run = function () {
    return this.name + 'Running';
  }
}
Fun();
console.log(window)Copy the code

It’s just calling a function, this refers to the window in non-strict mode, and you can find all the variables in the window object.

In addition, the prototype object’s method this points to the instance object, because the instance object’s __proto__ already points to the prototype function’s prototype. This brings us to the prototype chain, where methods look up along the prototype chain of objects.

Arrow function

I just mentioned that the arrow function is a typical example of not changing this with call and apply.

Let’s look at the following 🌰 :

var a = 1;
var obj = {
  a: 2
};
var fun = (a)= > console.log(this.a);
fun();/ / 1
fun.call(obj)/ / 1Copy the code

Above, both calls are 1.

So how do we determine this of the arrow function? The arrow function captures the this value of its context as its own this value, which means that the arrow function’s this is lexically bound. The apply, call methods just pass in arguments, but do not change this.

var a = 1;
var obj = {
  a: 2
};
function fun() {
    var a = 3;
    let f = (a)= > console.log(this.a);
      f();
};
fun();/ / 1
fun.call(obj);/ / 2Copy the code

As above, fun is called directly, and the value of this in the context of fun is window. Note that this is a bit convoluted. The context of fun is the context of the arrow function, so this of F is fun’s this, which is the window. When fun.call(obj) is called again, a new context is created, and fun’s this is obj, which is the arrow function’s this value.

One more 🌰 :

function Fun() {
    this.name = 'Damonare';
}
Fun.prototype.say = (a)= > {
    console.log(this);
}
var f = new Fun();
f.say();//windowCopy the code

This should refer to the instance f. No, the arrow function is in the context of __proto__, which is the context of Object, and Object’s this value is the global Object.

So here’s another 🌰:

function Fun() {
    this.name = 'Damonare';
      this.say = (a)= > {
        console.log(this); }}var f = new Fun();
f.say();// An instance of FunCopy the code

As shown above, the context of this.say becomes the context of Fun, because when the function is called as a constructor (which is what new does) the context of this points to the instance object.

Afterword.

The definition of the article are personal summary, improper place also please elegant.

Please indicate the source of reprint.

The above.