This is the fourth in a series of questions that you may have missed, but can be found here:

  • The difference between pseudo class and pseudo element and actual practice
  • How do I implement a Grail layout?
  • Today’s top interview questions and train of thought analysis

In front-end interviews, you will often be asked questions about the direction of this. Recently, my friend Z asked me for help, saying that he was confused as soon as he saw the title of “this” and couldn’t figure out who “this” actually referred to. I did the answer for him, and organized this article, hoping to help the students in need.

An Interview Question

My friend Z showed me the following problem:

var length = 10; function fn () { console.log(this.length); } var obj = { length: 5, method: function (fn) { fn(); arguments[0](); }}; obj.method(fn, 1);

Q: What is the output of the browser?

The answer is: print a 10, then a 2.

Let’s break down why:

  • In our case, although fn is passed in as a parameter to method, its caller is not affected, stillwindowSo it prints 10.
  • arguments[0]();This is not a very common statement, so maybe you’re confused here. In fact,Arguments is a special object. In the function, we do not need to specify the parameter name, can access. You can think of it as an implicit form of argument passing.
  • When performing the arguments [0] (); Fn () is actually called when. In this case, the fn function this refers to arguments, the special object. The obj.method method accepts two arguments, so the length of arguments is obviously 2.

modified

Again, many students are confused about the direction of this, because this does not point to the object we expect.

As in this case, semantically, we expect fn() to output the length of obj itself, which is 5, not 10. So if we want to get to 5, how do we change this code?

In fact, it just takes one more step. That is to make this point to obj itself. Here, we can use call to change the direction of this, as follows:

var length = 10; function fn () { console.log(this.length); } var obj = {length: 5, method: function (fn) {var obj = {length: 5, method: function (fn); }}; obj.method(fn);

And the output is going to be 5. Done.

See, this is not that complicated, we just need a few simple operations, we can control the direction of this. So, why does this sometimes get out of hand?

In fact, this has to do with the principle behind the this mechanism. But wait, let’s start by understanding the basic concept of this. First, what is this?

What is this?

This is a keyword in JavaScript. It is usually applied to the body of a function and depends on the context of the call and how the function is called. Who it points to is entirely determined by the point at which the function is called.

So, this is bound at run time, not at write time. The value of this can vary depending on where the function is used. But there is one general rule: this always refers to the object on which the function is called.

Why this?

Conceptually, it seems a little hard to understand. So why do we use this? What are the benefits of using this?

Let’s start with the following example:

function identify() {
    return this.name.toUpperCase();
}

var me = {
    name: "Kyle"
};

var you = {
    name: "Reader"
};

identify.call( me ); // KYLE
identify.call( you ); // READER

At first we may not understand why we output this way. Instead of using this, we can explicitly pass the environment object to identify(). Like this:

function identify(context) {
    return context.name.toUpperCase();
}
identify( you ); // READER

In this simple example, the result is the same. We can pass the environment object directly into the function, which is intuitive. However, as the schema becomes more complex, passing the execution environment as an explicit parameter to the function becomes very confusing.

The this mechanism, on the other hand, provides a more elegant way to implicitly “pass” a reference to an object, which makes API design cleaner and reuse easier.

The principle of this

After understanding the concept of this, it makes me wonder why this refers to the execution environment of the function operation.

Before, I saw an article written by Teacher Ruan, which thoroughly analyzed the principle of this. According to my own understanding, the arrangement is as follows.

Many textbooks will tell you that this refers to the environment in which the function is run. But why? In other words, how is the environment in which the function is run determined?

Understanding how this works helps us better understand its use. The reason why JavaScript language has this design has to do with the data structure in memory.

Take a look at a simple example:

var obj = { foo: 5 };

The above code assigns an object to the variable obj. The JavaScript engine generates an object {foo: 5} in memory and assigns the object’s memory address to the variable obj.

In other words, the variable obj is really just an address. To read obj.foo later, the engine gets the memory address from obj, and then reads the original object from that address, returning its foo property.

The structure is clear, but what if the value of the property is a function? Like this:

var obj = { foo: function () {} };

At this point, the JavaScript engine keeps the function separately in memory and assigns the function’s address to the value attribute of the foo attribute.

As you can see, the function is a single value (assigned as an address), so it can be executed in different environments.

This is because JavaScript allows you to refer to other variables in the current environment, inside the body of a function. So you need a mechanism to get the current context inside the body of the function. Thus, this appears, and is designed to refer to the context in which the function is currently running, within the body of the function.

This usage

Now that we understand how this works, let’s discuss the use of this in the following five situations.

1. Pure function calls

This is the most common use of a function and is a global call, so this represents the global object window.

function test(){ this.x = 1; console.log(this.x); } test(); / / 1

2. Call as an object method

Function is called as a method on an object, in which case this refers to the parent object.

function test(){ console.log(this.x); } var o = {}; o.x = 1; o.m = test; o.m(); / / 1

3, Called as a constructor

A constructor is a function that generates a new object. In this case, this refers to the new object.

function test(){ this.x = 1; } var o = new test(); console.log(o.x); / / 1

4, Apply call

Apply () is a method on a function object that changes the object on which the function was called. Its first argument is the object on which the function was called. Therefore, this refers to the first parameter.

var x = 0; function test() { console.log(this.x); } var o = {}; o.x = 1; o.m = test; o.m.apply(); / / 0

When the argument to apply() is null, the global object is called by default. Therefore, the result of this is 0, proving that this refers to the global object.

It has the same function as “call”, but it’s written differently. For space’s sake, I’ll open a separate article detailing their use.

5. Arrow function

The arrow function in ES6, for the most part, makes this point exactly as we expect it to. But sometimes it’s not a panch-all, and this can get out of hand if you’re not careful.

Because of the length of the content, I will write another article to introduce.

Another interview question

Finally, let’s solidify the concept and usage of this. Here’s an interview question:

window.val = 1; var obj = { val: 2, dbl: function () { this.val *= 2; val *= 2; console.log('val:', val); console.log('this.val:', this.val); }}; Obj.dbl (); obj.dbl(); var func = obj.dbl; func();

The answer is output: 2, 4, 8, 8.

Resolution:

  • Perform obj. DBL (); This in this.val refers to obj, and val in the next line refers to window. So, window.val prints 2, obj.val 4.
  • The last line func(); The caller of is window. So now this in this.val refers to window.
  • Window.val = 2; window.val = 2; window.val = 2; window.val = 2; window.val = 2; The result is 4.
  • val *= 2; That’s 8. So, the end result is the output of 8 and 8.

conclusion

This refers to the context in which the function is currently running and is bound at run time, depending on the context of the function call. Remember the general rule: this always refers to the object on which the function is called.

reference

  • This and the object prototype
  • JavaScript’s this principle

PS: Welcome to pay attention to my official account “Super Brother front-end stack”, to exchange more ideas and technology.