The understanding of this

The first thing to understand is that this is bound when the function is called, depending on where the function is called. This is the opposite of static scoping and is somewhat similar to dynamic scoping (which is determined by the runtime). This is bound to the object at run time.

Second, there is the common this pointing problem, the binding of this.

The binding rule for this

The default binding

You might be wondering what is the default binding? In non-strict mode, the function runs globally, and the “this” inside the function points to the Window object.

var a = I'm a in the global context.;
function fun() {
  console.log(this);
  console.log(this.a);
}
fun()
/ / the Window object
// I am a in the global context
Copy the code

As you can see from the “this” output from fun, the global function runs independently, and the internal “this” is bound to the window object.

In strict mode, the function calls this internally asundefined(a) call to global variable a;

Implicit binding

Implicit binding takes into account the presence or absence of context objects. When a function references a context object, the implicit binding binds this to that context object.

var a = 0
function fun() {
  console.log(this.a);
}
let obj = {
  a: 1.fun: fun,
}
obj.fun() / / 1
Copy the code

The function fun is declared globally and is added to obj as a reference property. Strictly speaking, fun does not belong to an obj object, whether it is declared globally or in obj’s fun.

Look primarily at the context object in which the function is called.

In the example above: the function is called inside obj, obj.fun(). The context object for fun() is obj, and this refers to the literal obj. So the output is the variable A inside obj.

var a = 0
function fun() {
  console.log(this.a);
}
let obj = {
  a: 1.fun: fun,
}
let o = obj.fun
o() / / 0
Copy the code

In this example, save obj.fun as a global variable and run the global variable later. At run time, the context object is the global Window. So this in fun, which points to window, outputs the global a variable 0. Of course, this example needs to be run in non-strict mode, otherwise the object bound to this is lost and undefined.

Explicitly bound

If you want to force a function to be called from an object, bind this to that object. We can use call(), apply(), and pass in the object to which we want to bind this. Specifies the object to which this refers directly.

let a = 'the window of a'
function fun() {
  console.log(this.a);
}
let obj = {
  a: A in 'obj '
}
fun.call(obj) // a in obj
fun.apply(obj) // a in obj
Copy the code

The first argument in both cases is the object to which this refers. The difference between call() and apply() is that the arguments passed are different. The call() method takes arguments, respectively, while the apply() method takes arguments in the form of an array. The implementation of call() and apply() will be explained in more detail later.

The new binding

Constructor: an ordinary function that is called with the new operator. It does not belong to a class, nor does it instantiate a class. It is important to note that there are no constructors, only constructor calls to functions.

How new works in js: If the function has no other return object, then the call to the function in the new expression will automatically return this new object.

Here, we are mainly talking about this.

function Fun(a) {
  this.a = a
}
var obj = new Fun(2)
console.log(obj.a);  / / 2
Copy the code

With the new binding, obj calls Fun(), where this points to obj. So the variable obj contains the a attribute. A outputs 2.

Binding priority

It goes without saying that the default binding has the lowest priority.

Implicit binding is compared to explicit binding

let a = 'the window of a'
function fun() {
  console.log(this.a);
}
let obj = {
  a: A in 'obj '.fun: fun
}
let test = {
  a: 'a' in the test
}
obj.fun() // a in obj
obj.fun.call(test) // a in test
Copy the code

Call changes this in obj’s fun function, pointing to this.a in test. Therefore, explicit binding takes precedence over implicit binding.

The implicit binding is compared to the new binding

function fun(a) {
  this.a = a
  console.log(this.a);
}
let obj = {
  a: A in 'obj '.fun: fun
}
obj.fun(obj.a) // a in obj
let o = new obj.fun(A 'o') // A in O
Copy the code

In new obj.fun(the a in ‘o ‘), new transfers obj, which was bound to this, to the o variable. And assign a value to the a attribute inside o, that is, a in O.

Show binding and new binding comparison

You cannot test it directly with new fun.Call (OBj), but you can test it with the bind binding.

function fun(a) {
  this.a = a
  console.log(this);
}
var obj = {}
var bar = fun.bind(obj)
bar(2)
console.log(obj.a);
var baz = new bar(3)
console.log(baz.a);
/ / the result
// {a: 2}
/ / 2
// fun {a: 3}
/ / 3
Copy the code

When you use bind,this points to obj, and you can see that this is {a: 2}. When new, we modify bind to point this to baz. So we have this new object baz.

Conclusion:

New binding > Explicit binding > Implicit binding > Default binding

Arrow function

The arrow function does not bind this according to the rule above, but rather determines this according to the lexical scope (static scope). The arrow function inherits the this binding from the outer function call. Same as using a variable to hold the this mechanism.

 function fun() {
  setTimeout(() = > {
    console.log(this);
  }, 0)
  setTimeout(function () {
    console.log(this);
  }, 0)}let obj = {
  a: "A" in the obj.fun: fun
}
obj.fun()
// {a: "a in obj ", fun: ƒ}
// Window
Copy the code

As you can see from the above example, the first setTimeout that uses the arrow function refers to obj by this. You can also think of the arrow function as a function expression, using this as fun refers to.

Reference books: “You don’t know JavaScript” on the voucher