The Magic This_javascript technique in JavaScript

Source: Internet
Author: User
Tags function prototype

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

1. Mistakenly think this point to the function itself

According to the English grammar of this, it is easy to interpret this as the function itself. In JavaScript, a function is a first-class citizen, and it is true that the property value is stored when invoked. However, if the use method is not correct, there will be a situation that is inconsistent with the actual expectation. For details, please see the code below

  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, then the property value of the Count property should be changed, but in fact it is motionless. Some people use scopes 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 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 of these methods output the correct results, they avoid the problem where this is bound. If the working principle of a thing is not clear, it will often produce headache treatment head, foot pain to the problem of foot, resulting in the code become ugly, and maintenance will become very poor.

2. This magical binding rule

2.1 Default binding rules

The first is the most common binding of this, look at the following code

  function fn () {
    console.log (window = = this);//Browser Environment
  }
  fn ();//true

The function fn is directly lowered in the global scope with no other adornments, in which case the function call uses the default binding of this, pointing to the global object.

This makes it clear that this point in the first example points to the global variable, so the this.count++ is equivalent to window.count++ (under the browser environment) and certainly does not affect the Count property of the FN function.

One thing to note is that the above conditions can only occur in strict mode, and in strict mode, the this default is bound to undefined. To avoid the pollution of global variables.

2.2 An implicit binding rule

If a function is invoked in the context of an object, the binding of this will change. This will bind to the object that called the function and view the following code:

  var obj = {
    a:1,
    fn:function () {
      console.log (THIS.A);
    }
  }
  
  Obj.fn (); 1

This point will still change even if the function declaration is not in the object

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

Thus, the binding of this is not related to the position defined by the function, but to the caller and the method of invocation.

Under implicit binding rules, there are some special places to be aware of.

2.2.1 Multi-Layer object Call this point

  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 a Multi-tier object reference, this points to the object of the called function.

2.2.2 Implicit assignment may be missing

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 is called without any modification, so this is still bound to the window.
There is also a situation, easy for everyone to ignore, that is, when the argument, in fact, will be implicitly assigned.

 function fn () {
    console.log (this);
  }
  
  function Dofn (FN) {
    fn ();
  }
  
  var obj = {
    fn:fn
  }
  
  dofn (OBJ.FN);//window

Implicit binding this is not a very recommended way, as it is very likely that a loss will occur, and if the binding to this is required in the business, it is recommended to use a display binding.

2.3 An explicit binding rule

A display binding is a binding of this using the Apply and call methods on the function prototype. The usage is to pass in the object that you want to bind as the first argument.

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

There are times when you want to bind a function's this to an object, but you don't need to call it immediately, so it's not possible to use calls or apply directly.

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

The example above, which seems to be possible, but actually the bind function is bound to the object of obj, but FN is still not any modification of the call, 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 this can be tightly controlled, because the invocation of FN is invoked by the apply. So, this is bound to the incoming obj object, and in the ES5, the function's prototype method has one more bind. The effect is basically the same as the function above, and the specific usage is limited to the length of the word.

2.4 New binding

New is a keyword that many people misunderstand, but in reality JavaScript new is completely different from the traditional object-oriented language.
A person understands new as a special function call, and when the new keyword is used to invoke the function, the following action is performed.

    • Create a new object
    • To point the __proto__ of the empty object to the prototype of the constructor
    • Bind this new object to the called function
    • If the function returns a value of the base type or for this or does not return any value, the new object created will be returned, and if an object is returned, the object will be returned without returning the new object created.
  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 parameters for communication

Null and undefined are also binding objects that can act as this, but in practice the default bindings are applied.
But what is the actual utility of such a reference?
A common use is to expand an array as a parameter to pass in parameters. Like what

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

But there is a hole in this usage, that is, if the function exists this, then the default binding rule is applied and the this is bound to the global object, which occurs in the expected inconsistency. For the code to be more robust, you can create an object that is more empty than the empty object.

var obj = object.create (null);
Console.log (obj.__proto__); Undefined

var obj2 = {}
console.log (obj2.__proto__);//object {}

The object prototype has a create method that creates an object and then points the object's prototype to an incoming argument, so passing in null generates an object with no prototype, so it is more "empty" than the empty object.

So passing in this object would be more secure than incoming null.

var obj = object.create (null);

Fn.apply (obj,[1,2]);

2.6 The binding of this is determined by scope

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

If you use the arrow functions, you will not use the four this binding method mentioned above, but rather depending on the scope of the

More common is the case for event functions and timers.

Here are the more common traditional this notation

  function fn () {
    var _this = this;
    settimeout (function () {
      console.log (_THIS.A);
    },100)
  }

  var obj = {
    a:2
  }
  
  fn.call (obj); 2
  

You can write this if you use the arrow function

  function fn () {
    settimeout () =>{
      //this from the scope of the FN function
      console.log (THIS.A);
    },100)
  }

  var obj = {
    a:2
  }
  
  fn.call (obj);//2

2.7 The binding mechanism of this in the event function

If it is in an event function, the binding of this is to point to the DOM element that triggers the event,

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

When you click the BODY element, the console displays the BODY element

3. Summary

If you want to determine where the this binding of a function is, first you find the call location of the function, followed by the rules.

    • If a function call does not have any cosmetic conditions, it is bound to undefined in strict mode, and is bound to the global under strict mode.
    • If the function is invoked with the object as the context, then it is bound to the object being invoked.
    • If called using the call or Apply method, it is bound to the first incoming parameter.
    • If the function is invoked using the New keyword, it is bound to the newly created object.
    • If it is within an event function, it is bound to the DOM element that triggered the event.

The above is about the magic of JavaScript in the relevant introduction, I hope to help you learn.

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.