资讯专栏INFORMATION COLUMN

你不知道的this

terasum / 1405人阅读

摘要:本内容来自你不知道的上卷,做了简单的总结。如果不使用这段代码该如何写呢那就需要给和显示传入一个上下文对象对比发现提供了额一种更优雅的方式来隐式传递一个对象引用。四总结随着你使用的模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱。

本内容来自《你不知道的JavaScript(上卷)》,做了简单的总结

this关键字是javascript最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有的函数作用域中。但是即使是非常有经验的javascript开发者也很难说出他到底指向什么。本节将分三个部分讲解javascript中的this:

为什么要使用this

两种常见的对于this的误解

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到底是个什么玩意?

通过排除以上种种的误解,我们可以得出以下结论:

this是在运行时进行绑定的,并不是在编写时绑定的

this的绑定和函数声明的位置没有关系,只取决于函数的调用方式

具体细节是:当一个函数被调用时,会创建一个活动记录(也称执行上下文(context))。这个记录会包含一些信息,比如: 函数在哪里被调用(调用栈), 函数的调用方式, 传入的参数等,而this就是这个记录的一个属性,会在函数执行过程中被用到。

四、总结

随着你使用的模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱。因此,通过使用this隐式传递可以将API设计的更加简洁并且易于复用

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

this实际上是函数被调用时发生的绑定,它的指向完全取决于函数在哪里被调用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78912.html

相关文章

  • 你不知道Virtual DOM(五):自定义组件

    摘要:现在流行的前端框架都支持自定义组件,组件化开发已经成为提高前端开发效率的银弹。二对自定义组件的支持要想正确的渲染组件,第一步就是要告诉某个标签是自定义组件。下面的例子里,就是一个自定义组件。解决了识别自定义标签的问题,下一步就是定义标签了。 欢迎关注我的公众号睿Talk,获取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、...

    lk20150415 评论0 收藏0
  • 你不知道Virtual DOM(六):事件处理&异步更新

    摘要:如果列表是空的,则存入组件后将异步刷新任务加入到事件循环当中。四总结本文基于上一个版本的代码,加入了事件处理功能,同时通过异步刷新的方法提高了渲染效率。 欢迎关注我的公众号睿Talk,获取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 目前最流行的两大前端框架,React和Vue,都不约而同的借助Virtual DO...

    caozhijian 评论0 收藏0
  • 你不知道JavaScript》 (下) 阅读摘要

    摘要:本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅不错,下册的知识点就这么少,非常不推介看下册上中下三本的读书笔记你不知道的上读书笔记你不知道的中读书笔记你不知道的下读书笔记第三 本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 不错,下册的知识点就这么少,非...

    Jacendfeng 评论0 收藏0
  • 你不知道javascript》笔记_this

    下一篇:《你不知道的javascript》笔记_对象&原型 写在前面 上一篇博客我们知道词法作用域是由变量书写的位置决定的,那this又是在哪里确定的呢?如何能够精准的判断this的指向?这篇博客会逐条阐述 书中有这样几句话: this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式当一个函数被调用时...

    cpupro 评论0 收藏0
  • 你不知道JavaScript》 (上) 阅读摘要

    摘要:但是如果非全局的变量如果被遮蔽了,无论如何都无法被访问到。但是如果引擎在代码中找到,就会完全不做任何优化。结构的分句中具有块级作用域。第四章提升编译器函数声明会被提升,而函数表达式不会被提升。 本书属于基础类书籍,会有比较多的基础知识,所以这里仅记录平常不怎么容易注意到的知识点,不会全记,供大家和自己翻阅; 上中下三本的读书笔记: 《你不知道的JavaScript》 (上) 读书笔记...

    FingerLiu 评论0 收藏0
  • 你不知道javascript (1) --- this

    摘要:的定义执行上下文。这本书也是举了好几个例子来说明,这句话的含义。我个人也认为,不通过代码,非常难说明问题。所以,修改的是全局的,并不是自身的。 this 先说明一下,this是我JavaScript的盲区,写这篇文章,就是为了让自己能重新认识this,并且搞清楚,js里面的this,到底是什么。 这个系列主要是记录我自己看《你不知道的JavaScript》这本书的笔记。 this的定义...

    Corwien 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<