Learn to master the use of this in JavaScript _javascript tips

Source: Internet
Author: User
Tags closure sessionstorage

Tip

First of all, I know this article is very boring, nothing more than the this in JS, and there have been thousands of articles have written this part of the content;
However, I still want to write a about JS in this article, is a summary summed up it; (the gods can detour to see my other articles)
In JS, this context is always unpredictable, many times the bug is always confused, in fact, as long as the difference between the circumstances of how the implementation of the OK.

Global execution
first, let's look at what this is in the global context:
First. Browser:

Console.log (this);

Window {speechsynthesis:speechsynthesis, caches:cachestorage, Localstorage:storage, Sessionstorage:storage, Webkitstorageinfo:deprecatedstorageinfo ...} 

You can see that the Window object is printed out;

Second. Node

 Console.log (this);

Global 

You can see that the global object is printed out;

Summary: in the global scope it executes the current global object (the browser-side is global in Window,node).

function to execute the
Pure Function call
This is the most common method of using a function:

 function test () {
 console.log (this);
};

Test ();

Window {speechsynthesis:speechsynthesis, caches:cachestorage, Localstorage:storage, Sessionstorage:storage, Webkitstorageinfo:deprecatedstorageinfo ...} 

We can see that when a function is called directly, it belongs to the global call, at which point it points to the global object;

Strict mode ' use strict ';

If pure function calls are performed in strict mode, this here does not point to the global, but undefined, which is done to eliminate some of the less rigorous behavior in JS:

 ' Use strict ';
function test () {
 console.log (this);
};

Test ();

Undefined 

Of course, it would be better to put it in an immediate execution function, avoiding the pollution overall:

 (function () {
 ' use strict ';
console.log (this);
}) ();

Undefined 

method call as an object
When a function is called as a method of an object:

 var obj = {
 name: ' QIUTC ',
 foo:function () {
 console.log (this.name);
 }

Obj.foo ();

' QIUTC ' 

This time, this points to the current object;

Of course, we can still do this:

 function test () {
 console.log (this.name);
}
var obj = {
 name: ' QIUTC ',
 foo:test
}

Obj.foo ();

' QIUTC ' 

Also unchanged, because in JS everything is an object, the function is also an object, for test, it is just a function name, function reference, it points to this function, when foo = Test,foo also points to this function.

If you assign the object's method to a variable, then call the variable directly:

 var obj = {
 name: ' QIUTC ',
 foo:function () {
 console.log (this);
 }

var test = Obj.foo;
Test ();

Window 

As you can see, this is the global, and when we put test = Obj.foo, test directly points to a reference to a function, this is not actually related to the object of obj, so it is called directly as a normal function, so this points to the global object.

some pits

We often encounter some holes in the callback function:

 var obj = {
 name: ' QIUTC ',
 foo:function () {
 console.log (this);
 },
 foo2:function () {
 Console.log (this);
 SetTimeout (This.foo, 1000);
 }

Obj.foo2 (); 

Execute this code we will find two times the printed this is not the same:

The first time is to print this directly in the Foo2, which points to obj, we have no doubt;

But the this.foo that is executed in the settimeout is pointing to the global object, isn't it used as a function method? This often makes many beginners puzzled;

In fact, settimeout is just a function, the function must probably need parameters, we this.foo as a parameter to settimeout this function, as it needs a fun parameter, in the passing of the parameter, actually do a operation fun = This.foo, see no, here we direct the fun to the This.foo reference; execution is actually performed fun () so it has nothing to do with obj, it is called directly as a normal function, so this points to the global object.

This problem is commonly encountered in many asynchronous callback functions;

Solve
To solve this problem, we can use the characteristics of the closure to deal with:

var obj = {
 name: ' QIUTC ',
 foo:function () {
 console.log (this);
 },
 foo2:function () {
 Console.log (this);
 var _this = this;
 settimeout (function () {
 console.log (this);//Window

 Console.log (_this);//Object {name: "QIUTC"}
 }, 1000);
 }

Obj.foo2 (); 

You can see directly with this is still Window, because this in Foo2 is pointing to obj, we can store it with a variable _this, then use _this in the callback function to point to the current object;

another pit in the settimeout

Before that, if you execute the callback function directly without binding the scope, then it is pointing to the Global Object (window) and pointing to undefined in strict mode, whereas the callback function in settimeout behaves differently in strict mode:

 ' Use strict ';
function foo () {
 console.log (this);
}
SetTimeout (foo, 1);

Window 

Logically we added strict mode, Foo call did not specify this, should be out of undefined, but here is still the global object, is the strict mode of failure?

No, even in strict mode, when the SetTimeout method calls into the function, if the function does not specify this, it does an implicit operation-automatically injecting the global context, equivalent to calling foo.apply (window) rather than foo ();

Of course, if we have specified this when passing in the function, we will not be injected into the global object, such as: SetTimeout (Foo.bind (obj), 1);;

Used as a constructor

In JS, in order to implement the class, we need to define some constructors that need to be added to the keyword when invoking a constructor:

 function person (name) {
 this.name = name;
 Console.log (this);
}

var p = new Person (' QIUTC ');

person {name: "QIUTC"} 

We can see that when called as a constructor, this points to an object instantiated at the time of the constructor call;

Of course, the constructor is actually a function, and if we execute it as a normal function, this one still performs the global:

 function person (name) {
 this.name = name;
 Console.log (this);
}

var p = person (' QIUTC ');

Window 

The difference is how to call the function (new).

Arrow Function

In the new specification of ES6, the arrow function is added, and the most unusual point of this is the point of this, remember that we use the closure to solve the point of this, and if we use the arrow function we can solve it more perfectly:

 var obj = {
 name: ' QIUTC ',
 foo:function () {
 console.log (this);
 },
 foo2:function () {
 Console.log (this);
 SetTimeout (() => {
 console.log (this);//Object {name: "QIUTC"}
 , 1000);
 }

Obj.foo2 (); 

As you can see, in the function that settimeout executes, this should print out in Window, but here this points to obj because the function (argument) passed to settimeout is an arrow function:

The This object in the body of the function is the object in which it was defined, not the object in which it was used.

From the example we understand this sentence:
When Obj.foo2 () executes, the current this points to obj; At the time of execution settimeout, we first define an anonymous arrow function, where the key point is this, the object in the arrow function where this execution is defined, is the one that is in the scope when the arrow function is defined. This, that is, obj in Obj.foo2, so this-> obj in this-> obj.foo2 when the arrow function is executed;

In simple terms, this in the arrow function is related to this in the scope that defines it, and it has nothing to do with where and how to invoke it, while its this point is immutable.

Call , apply, bind

In JS, the function is also the object, there are also some methods, here we introduce three methods, they can change the function of this point:
Call

Fun.call (thisarg[, arg1[, arg2[, ...)]]

It executes the function immediately, the first parameter is the context in which this is specified in the execution function, and the following argument is the argument that the function needs to be passed in;

Apply

Fun.apply (thisarg[, [Arg1, Arg2, ...]])

It executes the function immediately, the first parameter is the context in which this is specified in the execution function, the second argument is an array, the argument passed to the execution function (the difference from call);
Bind

var foo = fun.bind (thisarg[, arg1[, arg2[, ...)]];

Instead of executing the function, it returns a new function, which is specified in the context of this, followed by an argument that the execution function needs to pass in;

These three functions are very similar, and the general purpose is to specify the context of a function (this), and we take the call function as an example;

Specify this for a normal function

 var obj = {
 name: ' QIUTC '
};
function foo () {
 console.log (this);
}
Foo.call (obj);

Object {name: ' QIUTC '} 

As you can see, at the time of executing foo.call (obj), this in the function points to obj as the object, successful;

Specify a this for the method in the object

 var obj = {
 name: ' QIUTC ',
 foo:function () {
 console.log (this);
 }

var obj2 = {
 name: ' tcqiu222222 '
};

Obj.foo.call (OBJ2);

Object {name: ' tcqiu222222 '} 

As you can see, when the function is executed here the this point points to obj2, success;

Specify this for constructors

 function person (name) {
 this.name = name;
 Console.log (this);
}

var obj = {
 name: ' qiutc2222222 '
};

var p = new Person.call (obj, ' qiutc ');

Uncaught TypeError:Person.call is not a constructor (...) 

Here's a mistake because we went to new Person.call function, not person, where the function is not a constructor;

Try it with bind:

 function person (name) {
 this.name = name;
 Console.log (this);
}

var obj = {
 name: ' qiutc2222222 '
};

var Person2 = person.bind (obj);

var p = new Person2 (' QIUTC ');

person {name: "QIUTC"}

console.log (obj);

Object {name: ' qiutc2222222 '} 

The printed object is instantiated by person, and it has nothing to do with obj, and obj does not change, which means that we specify the this context to person and not take effect;

So it can be concluded that by using bind to assign this to a constructor, the this specified by the BIND function does not take effect at the time of the new constructor;

Of course bind can not only specify this, but also pass in parameters, let's try this operation:

 function person (name) {
 this.name = name;
 Console.log (this);
}

var obj = {
 name: ' qiutc2222222 '
};

var Person2 = person.bind (obj, ' qiutc111111 ');

var p = new Person2 (' QIUTC ');

person {name: "qiutc111111"} 

As you can see, although specifying this does not work, incoming parameters still work;

Specify this for the arrow function

Let's define a global arrow function, so this in the arrow function must point to the global object, and if you change this by using the call method:

 var Afoo = (a) => {
 console.log (a);
 Console.log (this);
}

Afoo (1);

1
//Window

var obj = {
 name: ' QIUTC '
};

Afoo.call (obj, 2);

2
//Window 

As you can see, the call pointing to this here is not successful, so you can conclude that the this in the arrow function has been determined (executing this in the scope that defines it), regardless of how and where it is invoked, including the call, apply, BIND) can not change it's this.

Just remember the arrow function Dafa good, invariant this.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.