你不知道的this

本内容来自《你不晓得的JavaScript(上卷)》,做了简朴的总结

this关键字是javascript最庞杂的机制之一。它是一个很迥殊的关键字,被自动定义在所有的函数作用域中。然则纵然黑白常有履历的javascript开发者也很难说出他究竟指向什么。本节将分三个部份解说javascript中的this:

  1. 为何要应用this

  2. 两种罕见的关于this的误会

  3. this究竟是什么

一、为何要应用this

在书中经由历程两段代码的对照来讲明为何要应用this。第一段代码以下:这段代码在差别的上下问对象(me和you)中重复应用函数identify()和speak(),不必针对差别的对象编写差别版本的函数。

function identify(){
      return this.name.toUpperCase();
  }
  function speak(){
      var greeting = "hello, I am " + identify.call(this);
      console.log(greeting);
  }
  var me = {
      name: "zhou"
  }
  var you = {
      name: "reader"
  }
  identify.call(me); //ZHOU
  identify.call(you); //READER
  speak.call(me); // hello, I am ZHOU
  speak.call(you); // hello, I am READER

假如不应用this, 这段代码该如何写呢?那就须要给identify()和speak()显现传入一个上下文对象

      function identify(cxt){
          return cxt.name.toUpperCase();
      }
      function speak(cxt){
          var greeting = "hello, I am " + identify(cxt);
          console.log(greeting);
      }
      identify(you); //READER
      speak(me); //hello, I am ZHOU

对照发明:this供应了额一种更文雅的体式格局来隐式“通报”一个对象援用。由于,跟着你应用的形式愈来愈庞杂,显式通报上下文对象会让代码变得愈来愈杂沓。因而,经由历程应用this能够将API设想的越发简约而且易于复用。

二、两种罕见的关于this的误会

误会1.指向函数自身

把this邃晓为指向函数自身,这个揣摸从英语语法角度是说的通的。
罕见的在函数内部援用自身的状况有:递归或者是一个在第一次被挪用后自身打仗绑定的事宜处理器。 JavaScript的新手开发者(比方说我)一般以为:既然能够把函数看做一个对象,那就能够在挪用函数时存储状况(属性的值)。
如今我们来剖析这个形式,让人人看到this并不像所想的那样指向函数自身。下面这段代码,我们想要纪录函数foo被挪用的次数:

      function foo(num){
          console.log("foo: " + num);
          this.count++; //纪录foo被挪用的次数
      }
      foo.count = 0;
      
      for(var i=0; i<10; i++){
          if(i > 5){
              foo(i)
          }
      }
       // foo: 6
       // foo: 7
       // foo: 8
       // foo: 9
      
       console.log(foo.count); // 0  为何会是0呢?

foo()函数中的console.log语句产生了4条输出,证实foo()确切被挪用了4次,但foo.count仍然是0,所以,仅从字面上来邃晓,this指向函数自身是毛病的。那末,题目的缘由是什么呢?
foo()函数是在全局作用域下实行的,this在这段代码中实在指向window,而且这段代码在无意中建立了一个全局变量count,他的值为NaN。
那末,碰到如许的题目很多的开发者(包括我),不会深切的思索为何this的行动和预期的不一致,也不会回复那些很难处理,但非常重要的题目。这里供应了三种处理这个题目的要领,个中前两种要领回避了this的寄义和事情道理。代码以下:

要领一 应用作用域(词法作用域)要领,该要领处理了我们碰到的题目,然则却没有直面this。

     function foo(num){
          console.log("foo: " + num);
          data.count++; //纪录foo被挪用的次数
      }
      var data ={
       count: 0
      };
      
      for(var i=0; i<10; i++){
          if(i > 5){
              foo(i);
          }
      }
       // foo: 6
       // foo: 7
       // foo: 8
       // foo: 9
      console.log(data.count);// 4

要领二 建立一个指向函数对象的词法标识符(变量)来援用它。一样该要领依旧回避了this的题目。

    function foo(num){
          console.log("foo: " + num);
          foo.count++; // foo指向它自身
      }
      foo.count = 0;
      for(var i=0; i<10; i++){
          if(i > 5){
              foo(i);
          }
      }
       // foo: 6
       // foo: 7
       // foo: 8
       // foo: 9
      console.log(foo.count);// 4

要领三 既然我们晓得this在foo函数实行时指向了别处,那末我们须要做的就是强迫this指向foo函数.

function foo(num){
          console.log("foo: " + num);
          this.count++;
      }
      foo.count = 0;
      for(var i=0; i<10; i++){
          if(i > 5){
              foo.call(foo, i); //应用call()能够确保this指向函数自身
          }
      }
       // foo: 6
       // foo: 7
       // foo: 8
       // foo: 9
      console.log(foo.count);// 4

此次我们从this的角度处理了题目。

误会2.指向函数作用域

第二种罕见的误会是:this指向函数作用域。这个题目有点庞杂,由于在某种状况下它是准确的,但在其他状况下他倒是毛病的
但一定要邃晓,this在任何状况下都不指向函数的作用域,在javascript内部作用域和对象确切很类似,可见的标识符都是他的属性,但作用域“对象”没法经由历程JavaScript代码接见,它存在于JavaScript引擎内部
在文中给出了如许一段代码:

    function foo(){
         var a = 2;
         this.bar();
    }
    function bar(){
        console.log(this.a);
    }
    foo(); // ReferenceError: a is not defined

这段代码试图经由历程this联通foo()和bar()的词法作用域,从而让bar()能够接见foo()作用域的变量a。but it’s impossible!

三、this究竟是个什么玩意?

经由历程消除以上各种的误会,我们能够得出以下结论:

  1. this是在运行时举行绑定的,并非在编写时绑定的

  2. this的绑定和函数声明的位置没有关系,只取决于函数的挪用体式格局

详细细节是:当一个函数被挪用时,会建立一个运动纪录(也称实行上下文(context))。这个纪录会包括一些信息,比方: 函数在那里被挪用(挪用栈), 函数的挪用体式格局, 传入的参数等,而this就是这个纪录的一个属性,会在函数实行历程中被用到。

四、总结

  1. 跟着你应用的形式愈来愈庞杂,显式通报上下文对象会让代码变得愈来愈杂沓。因而,经由历程应用this隐式通报能够将API设想的越发简约而且易于复用

  2. this既不指向函数自身,也不指向函数的作用域

  3. this实际上是函数被挪用时发作的绑定,它的指向完整取决于函数在那里被挪用

    原文作者:我仍旧在这里
    原文地址: https://segmentfault.com/a/1190000004611591
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞