Frontend BASICS (5): comprehensive explanation of this

Source: Internet
Author: User
In the process of learning JavaScript, we want to write it down in some ways because we do not have a clear understanding of some concepts, therefore, it is easy to rashly set some biased conclusions for these concepts to facilitate your memory.

During the execution context creation stage, the variable objects are generated separately, the scope chain is established, and this point is determined. The variable object and scope chain have been carefully summarized. The key here is to determine the point of this.

Here, we need to draw a very important conclusion that we must keep in mind that the point of this is determined when the function is called. That is, the execution context is determined when it is created. Therefore, we can easily understand that this point in a function can be very flexible. For example, in the following example, the same function points to different objects due to different calling methods.

var a = 10;var obj = {    a: 20}function fn () {    console.log(this.a);}fn(); // 10fn.call(obj); // 20

In addition, this cannot be changed once it is determined during function execution.

Var a = 10; var obj = {a: 20} function fn () {this = obj; // if you try to modify this statement, an error is reported in the console. log (this. a);} fn ();

1. this in the Global Object

This is a special global object that I mentioned before when summarizing the variable object. This in the global environment points to itself. Therefore, this is relatively simple, and there are not so many complicated cases to consider.

// Bind this to the global object this. a2 = 20; // The variable object is declared to be bound to the variable object, but in the global environment, the variable object is its own var a1 = 10; // only the value assignment operation is required, the identifier is implicitly bound to the Global Object a3 = 30; // all output results will comply with the expected console. log (a1); console. log (a2); console. log (a3 );

II. this in the function

Before summarizing this point in a function, I think it is necessary to use some strange examples to feel the uncertainty of this in the function.

// demo01var a = 20;function fn() {    console.log(this.a);}fn();
// demo02var a = 20;function fn() {    function foo() {        console.log(this.a);    }    foo();}fn();
// demo03var a = 20;var obj = {    a: 10,    c: this.a + 20,    fn: function () {        return this.a;    }}console.log(obj.c);console.log(obj.fn());

For these examples, you need to take some time to get started. If you don't want to understand what's going on for the moment, you don't have to worry about it. Let's analyze it at 1.1.

Before the analysis, we will directly throw a conclusion.

In a function context, this is provided by the caller and determined by the method of calling the function. If the caller function is owned by an object, the internal "this" of the function points to the object during the call. If the function is called independently, this in the function points to undefined. However, in non-strict mode, when this points to undefined, it is automatically pointed to a global object.

From the conclusion, we can see that it is critical to find the caller of the function and determine whether the caller is an independent call.

// For accurate judgment, we use the strict mode inside the function, because the non-strict mode will automatically point to the global function fn () {'use strict '; console. log (this) ;}fn (); // fn is the caller and calls window independently. fn (); // fn is the caller and is owned by window

In the preceding simple example, fn (), as an independent caller, points this internally to undefined according to the definition. While window. fn () is owned by window, the internal this points to the window object.

Now that you have mastered this rule, go back and look at the three examples above. By adding/removing the strict mode, you will find that this has become less illusory, there are traces to follow.

But we need to pay special attention to demo03. In demo03, the c attribute of object obj is calculated using this. a + 20, while its caller obj. c is not a function. Therefore, he does not apply to the above rules. We need to draw a separate conclusion on this method.

When obj is declared globally. where is c called? this points to the global object. When obj is declared in the function environment, this point is undefined. In non-strict mode, it is automatically redirected to the global object. Run the following example to check the difference.

'Use strict '; var a = 20; function foo () {var a = 1; var obj = {a: 10, c: this. a + 20, fn: function () {return this. a ;}} return obj. c;} console. log (foo (); // an error is reported during running.

In actual development, this is not recommended;

The strict mode mentioned above needs to be taken seriously, because in actual development, the strict mode is basically used now, and the latest ES6 also supports the strict mode by default.

Let's take a look at some examples of easy-to-understand errors to deepen our understanding of callers and whether they are running independently.

var a = 20;var foo = {    a: 10,    getA: function () {        return this.a;    }}console.log(foo.getA()); // 10var test = foo.getA;console.log(test());  // 20

In foo. getA (), getA is the caller. It is not called independently and owned by the object foo. Therefore, this points to foo. Test (), as the caller, is called independently even though it is referenced by foo. getA. Therefore, this points to undefined and automatically redirects to the global window in non-strict mode.

Modify the Code a little and you will understand it yourself.

var a = 20;function getA() {    return this.a;}var foo = {    a: 10,    getA: getA}console.log(foo.getA());  // 10

A new one. The following is an example.

Function foo () {console. log (this. a)} function active (fn) {fn (); // real caller, called independently} var a = 20; var obj = {a: 10, getA: foo} active (obj. getA );

3. Use call and apply to display the specified this

JavaScript provides a mechanism for you to manually set the point of this. They are call and apply. All functions have two methods. They have the same functions except for slightly different parameters. Their first parameters are all the objects that this will point.

The following is an example. Fn is not a method of object obj, but through call, We bind this In fn to obj, so we can use this. a to access the attribute of obj. This is the call/apply usage.

function fn() {    console.log(this.a);}var obj = {    a: 20}fn.call(obj);

The parameters after call and applay are transmitted to the function to be executed. Here, call is transmitted in the form of one, and apply is transmitted in the form of an array. This is their only difference.

function fn(num1, num2) {    console.log(this.a + num1 + num2);}var obj = {    a: 20}fn.call(obj, 100, 10); // 130fn.apply(obj, [20, 10]); // 50

Because of the existence of call/apply, JavaScript becomes very flexible. Therefore, call/apply has many useful scenarios. I would like to add a few points.

1. Convert the class array object to an array

Function exam (a, B, c, d, e) {// first, check the built-in attribute arguments of the function. What is the console like. log (arguments); // use call/apply to convert arguments to an array, and the returned result is an array. arguments itself does not change var arg = []. slice. call (arguments); console. log (arg);} exam (2, 8, 9, 10, 3); // result: // {'0': 2, '1': 8, '2': 9, '3': 10, '4': 3} // [2, 8, 9, 10, 3] //// this method is often used to convert the nodelist in DOM to an array. // []. slice. call (document. getElementsByTagName ('lil '));

2. modify this point flexibly as needed

var foo = {    name: 'joker',    showName: function() {      console.log(this.name);    }}var bar = {    name: 'rose'}foo.showName.call(bar);

3. Implement inheritance

// Define the parent constructor var Person = function (name, age) {this. name = name; this. age = age; this. gender = ['man ', 'Woman'];} // defines the subclass constructor var Student = function (name, age, high) {// use call Person. call (this, name, age); this. high = high;} Student. prototype. message = function () {console. log ('name: '+ this. name + ', age:' + this. age + ', high:' + this. high + ', gender:' + this. gender [0] + ';');} new Student ('xiaom ', 12, '123 '). message (); // result // ---------- // name: xiaom, age: 12, high: 150, gender: man;

I would like to explain it to my friends who have an object-oriented knowledge base. In the Student constructor, the call method is used to execute the parent constructor once, which is equivalent to copying the code in Person in Sudent, this indicates the new instance object from Student. The call method ensures that the point of this is correct, so it is equivalent to implementing the basic layer. Student constructor is equivalent to the following.

Var Student = function (name, age, high) {this. name = name; this. age = age; this. gender = ['man ', 'Woman']; // Person. call (this, name, age); this sentence is equivalent to the above three sentences, so it inherits this. high = high ;}

4. in the transfer to other execution contexts, ensure that the point of this remains unchanged.

In the following example, we expect that when getA is called by obj, this points to obj, but the existence of anonymous functions leads to the loss of this point, in this anonymous function, this points to the global, so we need to find some ways to find the correct this point.

var obj = {    a: 20,    getA: function() {        setTimeout(function() {            console.log(this.a)        }, 1000)    }}obj.getA();

The conventional solution is simple, that is, to use a variable to save the reference of this. We often use this method, but we also need to use the knowledge mentioned above to determine whether this has been modified in the transfer. If it has not been modified, there is no need to use it like this.

var obj = {    a: 20,    getA: function() {        var self = this;        setTimeout(function() {            console.log(self.a)        }, 1000)    }}

The closure and apply methods are used to encapsulate a bind method.

function bind(fn, obj) {    return function() {        return fn.apply(obj, arguments);    }}var obj = {    a: 20,    getA: function() {        setTimeout(bind(function() {            console.log(this.a)        }, this), 1000)    }}obj.getA();

Of course, you can also use the bind method that already comes with ES5. It has the same effect as the bind method encapsulated above.

var obj = {    a: 20,    getA: function() {        setTimeout(function() {            console.log(this.a)        }.bind(this), 1000)    }}

IV. this in constructors and prototype Methods

Almost all of us use this when encapsulating objects. However, only a few people understand the point of this in this process. Even if we understand the prototype, we do not necessarily understand this. Therefore, I think this part will be the most important and core part of this article. After understanding this, it will be of great help for you to learn JS object-oriented.

In combination with the example below, I will throw a few questions for your consideration.

Function Person (name, age) {// who points to this? This. name = name; this. age = age;} Person. prototype. getName = function () {// who does this point? Return this. name;} // are the two above this the same? Do they point to the prototype object? Var p1 = new Person ('Nick ', 20); p1.getName ();

We already know that this is determined during the function call process. Therefore, it is very important to understand what happened in the new process.

Calling constructor through the new operator goes through the following four stages.

1. Create a new object;

2. Point this of the constructor to this new object;

3. Point to the constructor code and add attributes and methods for this object;

4. Return the new object.

Therefore, when the new operator calls the constructor, this actually points to the newly created object, and finally returns the new object to be received by instance object p1. Therefore, we can say that this of the constructor points to the new instance object p1 at this time.

This in the prototype method is much easier to understand. According to the above definition of this in the function, getName in p1.getName () is the caller, And it is owned by p1. Therefore, this in getName, it also points to p1.

Well, all I know is that everything about this has been summarized. I hope you can learn something after reading it, and then give me a thumbs up ^_^. If you find any errors, please note in the comments that I will modify them as soon as possible. Thank you first.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.