Small knowledge, big challenge! This article is participating in the “[Essential Tips for Programmers]

During the development, do you feel that the direction of this is different from what you think? Here you will not feel that the direction of this is not so mysterious. Let’s uncover the mystery of this together.

above

I learned object-oriented languages like c++, Java and python when I was in college. When I switched from object-oriented thinking to JS, it was very difficult for me to understand this JS this. In my mind, this refers to the object itself, but in JS, this can change its orientation at any time. Let’s talk about the pitfalls of our thinking.

myth

Point to their own

Let’s start with some code:

var name = 'window'
function sbThis() {
  console.log(this.name); // window
}

sbThis.name = 'I am sbThis'

sbThis()
Copy the code

This is when we think that this should be our own in our mind, but this refers to the window.

scope

Here’s another code:

var name = 'window'
function sbThis() {
  var name =  'I am sbThis'
  this.sbThisNo2()
}

function sbThisNo2() {
  console.log(this.name); // window
}

sbThis()
Copy the code

SbThisNo2 we said sbThis was pointing to the window, so we can call sbThisNo2. When sbThisNo2 is called, we know that sbThisNo2 this refers to sbThis, which is wrong again. However, this kind of cognition sometimes is right, sometimes is wrong, look at this sbThis refers to window, this is the cognition in our mind. So we’re going to learn it with a set of rules for this.

content

Begin to learn the true direction of the content chapter this. Remember a word: observe where the function is used and make a judgment.

The four principles

The default binding

A piece of code:

var name = 'window'
function sbThis() {
  console.log(this.name); // window
}

sbThis.name = 'I am sbThis'

sbThis()
Copy the code

This is the default binding, when we call this function globally, so this refers to the window.

Implicit binding

Take a look at this code:

var name = 'window'
function sbThis() {
  console.log(this.name); / / I'm OBJ
}

var obj = {
  name: 'I am the OBJ.fn: sbThis
} 

obj.fn()
Copy the code

Here we call obj.fn. Here we can see that fn is called by obj. Here’s another piece of code:

var name = 'my window'
function sbThis() {
  console.log(this.name); / / my window
}

var obj = {
  name: 'I am the OBJ.fn: sbThis
} 
var falseFn = obj.fn
falseFn()
Copy the code

If I’m a little confused here, let me look at this code again:

var name = 'my window'
function sbThis() {
  console.log(this.name); / / my window
}

var obj = {
  name: 'I am the OBJ.fn: sbThis
} 
var falseFn = obj.fn
falseFn()
console.log(obj.fn === sbThis); // true
console.log(falseFn === sbThis); //true
Copy the code

There is a reference to sbThis that is changed to falseFn, which indicates that the sbThis function is running. Assigning a reference to this does not assign past, but simply assigns the word this.

One thing to be aware of is the hidden assignment.

var name = 'my window'
function sbThis() {
  console.log(this.name); / / my window
}

function sbThisNo2(fn) {
  fn()
}

var obj = {
  name: 'I am the OBJ.fn: sbThis
} 

sbThisNo2(obj.fn)
Copy the code

Functions as arguments are also operations that assign references.

Hard binding

Call, apply, and bind. Force this to bind.

We often forget the difference here.

First of all, their first argument is to bind this. The way I remember it is: a call is a phone call, so we need to say it sentence by sentence, and the corresponding parameters are passed one by one. I think of app. When we fill in personal information, we fill in all the information at one time. Corresponding to that, the second parameter is an array. Bind is a bind, it binds to a person, it forms a new individual, and the second argument, remember before that only one of them is an array and you just pass them one by one. This is my way of memorizing, generally not applicable to you, you see these words think of what to use this scene to memorize.

var name = 'my window'
function sbThis() {
  console.log(this.name); // OBJ * 3
}

var obj = {
  name: 'I am the OBJ.fn: sbThis
} 

sbThis.call(obj)
sbThis.apply(obj)
sbThis.bind(obj)()
Copy the code

New

In JavaScript a function is treated as an object, and when you use new to use a function, the function becomes a constructor, generating a new object.

function sbThis(name) {
  this.name = name
  console.log(this.name); / / I'm OBJ
}

const obj = new sbThis('I am the OBJ)
Copy the code

priority

In a word: New > Hard Binding > Implicit Binding > Default binding (see reference books for details)Copy the code

Rules of exception

There are some exceptions to the rule. What you think is the rule is the default binding.

The ignored this

var name = 'I am the window'
function sbThis() {
  console.log(this.name); / / I'm a window
}

sbThis.call(null)
Copy the code

When we use a hard binding and the first parameter is null or undefined, the hard binding fails and becomes the default binding.

Anonymous function this

var name = 'I am the window'
function sbThis() {
  setTimeout(function () {
    console.log(this.name); / / I'm a window
  },1000)}var obj = {
  name: 'I am the obj.fn: sbThis
}

obj.fn()
Copy the code

The this of an anonymous function refers to the window.

Arrow function

Change the above code to the arrow function:

var name = 'I am the window'
function sbThis() {
  setTimeout(() = > {
    console.log(this.name); / / I'm obj
  },1000)}var obj = {
  name: 'I am the obj.fn: sbThis
}

obj.fn()
Copy the code

Since the arrow function does not have this, it points to this in the parent scope.

practice

var className = 'window'
function Page(callBack) {
  callBack('callBack') // window callBack
  this.className = 'Page'
  callBack('callBack') // Page callBack
  this.MessageCallBack = callBack // 
  this.MessageCallBack('MessageCallBack') // Page MessageCallBack
}

function PageA() {
  this.className = 'PageA'
  this.handleMessage = function (msg) {
    console.log(this.className, msg)
  }
 Page(this.handleMessage)
}

new PageA()
Copy the code
  1. We did a new one firstPageA object.
  2. Using Page in the PageA objectThe default binding).
  3. The value of this. HandleMessage (Hidden assignments) to callBack.
  4. soBoth Page and callBack refer to window.

Change point code:

var className = 'window'
function Page(callBack) {
  callBack('callBack') // window callBack
  this.className = 'Page'
  callBack('callBack') // window callBack
  this.MessageCallBack = callBack // 
  this.MessageCallBack('MessageCallBack') // Page MessageCallBack
}

function PageA() {
  this.className = 'PageA'
  this.handleMessage = function (msg) {
    console.log(this.className, msg)
  }
 new Page(this.handleMessage)
}

new PageA()
Copy the code

Here we change the Page call to New Page. The logic is the same as before but with the new Page so this in the Page refers to the Page. However, callBack(implicit assignment) still refers to window. So this.className = ‘Page’ is not valid for subsequent printing.

conclusion

Let go of other languages and self-knowledge.

Follow four rules.

Keep looking.