This is the 7th day of my participation in the August Text Challenge.More challenges in August

Why this?

Let’s take a look at some code

var bar = { myName:"time.geekbang.com", printName: Function () {console.log(myName)}} function foo() {let myName = "geeky" return bar.printname} let myName = "geeky" let bar.printname} let myName = "geeky" let  _printName = foo() _printName() bar.printName()Copy the code

As a rule of thumb, most languages print the myName of the bar object instead of the global myName when they execute bar.printName(). JavaScript, on the other hand, outputs global variables because the scope chain of the JavaScript language is determined by lexical scope, which is determined by code structure.

It is a common requirement for methods inside objects to use properties inside objects, but JavaScript’s scoping mechanism does not support this. For this reason, JavaScript has a this mechanism to handle this.

How do you make a function in an object read a property in an object

var bar = { myName:"time.geekbang.com", printName: Function () {console.log(this.myname)}} let myName = 'global scope' bar.printName()Copy the code

That’s how you get it.

The first thing you need to understand is that the scope chain and this are two different systems, and there is not much connection between the two

What is this?

The execution context includes the variable environment, lexical environment and outer, but it also includes this.

This is bound to the execution context; each execution context has a this.

There are three execution contexts:

  • Global execution context
  • Function execution context
  • Eval Execution context

So there are three kinds of this

  • This in the global execution context
  • This in the context of function execution
  • This in the eval

Eval is used sparingly, mostly in the context of global execution and in the context of function execution

This in the global execution context

What is this in the global execution context that can be printed in the console

console.log(this) 
Copy the code

The output is actually the Window object, and the conclusion is that this in the global execution context refers to the window object, which is the only focus of this and the scope chain, the bottom of which contains the Window object, and this in the global execution context also refers to the Window object.

This in the context of function execution

function foo(){
  console.log(this)
}
foo()
Copy the code

Print this inside foo and find that this in both function execution context and global execution context refers to the window object. What about this, which can set the function execution context to point to another object? Yes, there are three ways to set the this pointer to the function execution context.

Set this to the function via the call method of the function

You can use the call method to set the function’s this pointer and execute it immediately, as in the following code

function foo(){
  this.name = "foo"
}
fooObj = {
  name:"fooObj"
}
foo.call(fooObj)
console.log(fooObj) //{name: "foo"}
Copy the code

Normally this refers to the window, but the call function changes the orientation of this from foo to fooObj, changing the name of fooObj from fooObj to Foo.

Set this to point to the current object via the object call method
Var Obj = {name: "Obj", getThis:function(){console.log(this)}} Obj.Copy the code

As you can see that the output this refers to the current object, you can conclude that you can use the object to call its internal method, whose this refers to the object itself.

You can also think of the JavaScript engine converting myObject.showthis to myObject.showthis

obj.getThis.call(obj)
Copy the code

What if you assign a function from an object to a global variable?

var Obj = {
  name:"Obj",
  getThis:function(){
    console.log(this)
  }
}
var foo =  Obj.getThis
foo()
Copy the code

Now we get the Window object again.

There are two conclusions

  • Call a function in the global environment. This inside the function refers to the global variable window
  • Call a method inside an object whose execution context this refers to the object itself.

That is, if you’re executing a function globally, this refers to the whole world, but if you’re inside an object, this refers to the object, depending on who called the function.

Through the constructor

Let’s say new an object

function Person(){
  this.name='P'
}
var p1 = new Person()
console.log(p1) //Person {name: "P"}
Copy the code

Do you know what the JavaScript engine does in the process of new an object?

  1. First, create an empty object p1
  2. Call Person.call(p1) so that this points to empty object P1 when the execution context of Person is created
  3. Execute the Person method, because this points to P1, so p1’s name=’p’
  4. Return the object P1

Design flaw in this

1. This of a nested function does not inherit this of an outer function

var Obj = { name:"Obj", getThis:function(){ console.log(this) function bar(){ console.log(this) } bar() } } Obj.getThis()//{name: "Obj", getThis: ƒ} //Window...Copy the code

Reworking the above code and adding a method bar to getThis, what does this point to in bar? You might think that this refers to Obj, but in fact bar’s this refers to the global Window object, and getThis’s refers to Obj. This is one of the most confusing things in JavaScript and a source of many problems.

How to solve such a problem? How can BAR have a variable pointing to Obj?

One way to do this is to store the this in getThis into a self variable and put it in bar
var Obj = { name:"Obj", getThis:function(){ console.log(this) self = this; Function bar(){self.name='bar' console.log(self)} bar()} obj.getThis ()//{name: "Obj", getThis: ƒ} //{name: ƒ} "Bar", getThis: ƒ}Copy the code

Bar self points to Obj, change the name in self so that Obj changes too. The essence of this method is to convert this system into a scoped system. Because when it gets to bar, bar will find self along the scope chain and then find self on getThis, and because getThis assigns this to self, it’s equivalent to bar taking getThis’s this, which points to Obj.

Another approach is to use the arrow function in ES6 to solve this problem
var myObj = {
  name : "Obj", 
  showThis: function(){
    console.log(this)
    var bar = ()=>{
      this.name = "bar"
      console.log(this)
    }
    bar()
  }
}
myObj.showThis()
console.log(myObj.name)
console.log(window.name)
Copy the code

This is also what we want nested functions to get to the outermost object. This is because the arrow function in ES6 does not create an execution context, which means that the arrow function does not have its own this; the arrow function’s this is retrieved from its external function.

To summarize, there are two ways to get the outermost object from a nested function

  • You can save this of the outer function as a variable and let the nested function get it
  • You can write a nested function as an arrow function that gets the this of the outer function

2. By default, the this of normal functions refers to the global object Window

The above are

function foo(){
  console.log(this)
}
foo()
Copy the code

That’s how it outputs the window object.

In practice, we don’t want this in the execution context of a function to point to a global object by default, which can cause some misoperations. If you want this in the execution context of a function to point to an object, the best way to do this is through the call method.

This can also be done in JavaScript strict mode, where a function is executed by default and this is undefined in the context in which the function is executed

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

One question. If you want to implement updateInfo, you can change userInfo. What’s wrong with this code

let userInfo = { name:"jack.ma", age:13, sex:male, UpdateInfo :function(){setTimeout(function(){this.name = "pony.ma" this.age = 39 this.sex = female },100) } } userInfo.updateInfo()Copy the code

The problem is that setTimeout is still a nested callback function, so you need to change it to an arrow function to find the correct this value.

Learn from: time.geekbang.org/column/arti…