The magic of this in Javascript, javascriptthis

Source: Internet
Author: User

The magic of this in Javascript, javascriptthis

This in Javascript is a completely different mechanism from other languages and may confuse engineers who write other languages.

1. mistakenly think this points to the function itself

According to the English syntax of this, it is easy to understand this in a function as the function itself. In javascript, functions, as first-class citizens, can indeed store attribute values during calls. However, if the method is incorrect, it will be inconsistent with the actual expectation. For more information, see the following code:

  function fn(num){    this.count++;  }    fn.count = 0;    for(var i=0;i<3;i++){    fn(i);  }  console.log(fn.count); // 0

If this in the fn function points to its own function, the attribute value of the count attribute should change, but it does not actually matter. Some people will use the scope to solve this problem, such as writing

  var data = {    count:0  };    function fn(num){    data.count++;  }    for(var i=0;i<3;i++){    fn(i);  }    console.log(data.count);  //3

Or write it more directly.

  function fn(num){    fn.count++;  }    fn.count = 0;    for(var i=0;i<3;i++){    fn(i);  }    console.log(fn.count);//3

Although both methods output the correct results, they avoided the question of where this was actually bound. If the working principle of a thing is unclear, it will often lead to headaches, headaches, and pain points, resulting in Code become ugly, and maintenance will become very poor.

2. this magic binding rule

2.1 default binding rules

The first is the most common binding of this. Check the following code in the response.

Function fn () {console. log (window = this); // browser environment} fn (); // true

Function fn is called directly in the global scope without any modification. In this case, the default binding of this is used when the function is called, pointing to the global object.

This makes it clear that this points in the first example, and this in the fn function points to the global variable, so this. count ++ is equivalent to window. count ++ (in a browser environment) does not affect the count attribute of the fn function.

One thing to note is that the above situation can only occur in non-strict mode. In strict mode, this is bound to undefined by default. To avoid global variable pollution.

2.2 implicit binding rules

If a function is called in the context of an object, the binding of this changes. This will be bound to the object that calls this function. view the following code:

  var obj = {    a:1,    fn:function(){      console.log(this.a);    }  }    obj.fn(); //1

Even if the function declaration is not in the object, this point will still change.

  function fn(){    console.log(this.a);  }  var obj = {    a:1,    fn:fn  }  obj.fn(); //1

It can be seen that the binding of this is not related to the position defined by the function, but to the caller and call method.

In implicit binding rules, there are some special points that need attention.

2.2.1 point of calling this for multi-layer objects

  function fn(){    console.log(this.a);  }  var obj = {    a:1,    obj2:obj2  }  var obj2 = {    a:2,    obj3:obj3  }  var obj3 = {    a:3,    fn:fn  }    obj.obj2.obj3.fn(); //3

Under multi-layer object reference, this points to the object of the called function.

2.2.2 implicit assignment may be lost

View the following code

  function fn(){    console.log(this);  }  var  obj = {    fn:fn  }    var fun = obj.fn;  fun(); //window

Although fn references obj. fun, the function call method still does not contain any modification, so this is bound to the window.
In another case, it is easy for everyone to ignore, that is, when passing the parameter, it will actually be implicitly assigned.

 function fn(){    console.log(this);  }    function doFn(fn){    fn();  }    var obj = {    fn:fn  }    doFn(obj.fn); //window

Implicit binding of this is not a recommended method, because it is very likely that this will be lost. If the business requires this binding, we recommend that you use the display binding method.

2.3 explicitly binding rules

Show binding is to use the apply and call methods on the function prototype to bind this. The usage is to pass the object to be bound as the first parameter.

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

Sometimes you want to bind this function to an object, but you do not need to call it immediately. In this way, you cannot directly use call or apply.

  function fn(){    console.log(this);  }    function bind(fn){    fn();  }    var obj = {    fn:fn  }    bind.call(obj,fn); //window

In the above example, it seems that this can be used, but in fact this of the bind function is bound to the object obj. However, fn still does not have any modification calls, so fn is still the default binding method.

  function fn(){    console.log(this);  }    function bind(fn,obj){    return function(){      fn.apply(obj,arguments);    }  }    var obj = {    fn:fn  }    var fun = bind(fn,obj);  fun(); //obj

In this way, the flexible and changing this can be controlled, because the fn call method is apply call. Therefore, this is bound to the input obj object. In ES5, a bind is added to the function prototype method. The results are basically the same as those of the above functions. The specific usage is limited by space.

2.4 new binding

New is a keyword that many people misunderstand, but in fact javascript's new is completely different from the traditional object-oriented language.
I personally think of new as a special function call. When the new keyword is used to call a function, the following operations are performed,

  • Create a new object
  • Point _ proto _ of an empty object to the prototype of the constructor.
  • Bind this of the new object to the called function.
  • If the return value of the function is of the basic type or this type, or no value is returned, the newly created object will be returned. If an object is returned, this object will be returned, instead of returning the created object.
  function fn(a){    this.a = a;  }  fn.prototype.hi = function(){    console.log('hi')  }    var obj = new fn(2);    console.log(obj);  function fn(a){    this.a = a;    return {};  }    var obj = new fn(2);    console.log(obj); //{}

2.5 Special parameter passing

Null and undefined can also be used as the binding object of this, but in fact the application is bound by default.
But what is the actual utility of passing parameters?
A common usage is to expand an array and pass in parameters as parameters. For example

  function fn(a,b){    console.log('a:',a,'b:',b);  }    fn.apply(null,[1,2]); // a: 1 b: 2

However, there is a pitfall in this usage, that is, if the function has this, the default binding rule will be applied to bind this to a global object, as expected. To make the code more robust, you can create an object that is more empty than a null object.

var obj = Object.create(null);console.log(obj.__proto__); //undefinedvar obj2 = {}console.log(obj2.__proto__); //Object {}

There is a create method on the Object prototype. This method creates an Object and points the Object prototype to the input parameter. Therefore, if null is input, an Object without prototype is generated, therefore, it is more "null" than a null object ".

Therefore, it is safer to pass in this object than to pass in null.

var obj = Object.create(null);fn.apply(obj,[1,2]);

2.6 determine the binding of this based on the scope.

In ES6, a new function type, arrow function appears.

If the arrow function is used, the above four this binding methods will not be used, but will be determined based on the scope.

It is usually used for event functions and timers.

The following are common methods of this writing.

  function fn(){    var _this = this;    setTimeout(function(){      console.log(_this.a);    },100)  }  var obj = {    a:2  }    fn.call(obj); //2  

If you use the arrow function, you can write it like this.

Function fn () {setTimeout () => {// this comes from the scope console of the fn function. log (this. a) ;}, 100)} var obj = {a: 2} fn. call (obj); // 2

2.7 this binding mechanism in event Functions

In the event function, this binding points to the DOM element that triggers the event,

$('body')[0].addEventListener('click',function(){  console.log(this);},false);

After you click the body element, the console displays the body element.

3. Summary

To determine where a function is bound with this, first locate the function call location, and then follow the rules.

  • If the function is called without any modification conditions, it will be bound to undefined in strict mode and global in non-strict mode.
  • If you use an object as the context to call a function, it is bound to the called object.
  • If the call or apply method is used for calling, it is bound to the first input parameter.
  • If the new keyword is used to call a function, it is bound to the newly created object.
  • If it is in the event function, it is bound to the DOM element that triggers the event.

The above is an introduction to the magic this in Javascript, and I hope it will help you learn it.

Articles you may be interested in:
  • Javascript this keyword Usage Analysis
  • Javascript this usage Summary
  • Javascript this pointer
  • Js error Object doesn' t support this property or method Cause Analysis
  • Onclick (this) usage in javascript
  • Details about the this keyword in js
  • Introduction to the use of this variable in JS
  • In-depth understanding of the scope of this in Javascript

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.