vue的生命周期函数不能使用箭头函数

news2024/11/26 16:58:34

如果使用过react和vue,应该发现过一个问题:vue告诉我们不应该把方法、生命周期用箭头函数去定义;而在react的类组件中,把方法写成箭头函数的形式却更方便。

要问其原因,大部分人都只把他当一个理所当然的规定。但把这个问题剖开,其实能很好地把准备面试时造的火箭,在拧螺丝的时候用起来。

这篇文章可以让你在这个实际场景中去用到this的指向、作用域链以及原型。

this指向丢失

无论是vue还是react,都在官方文档中强调,需要注意this的指向丢失。但有趣的是,为了达到同样的目的,一个是不能使用箭头函数,一个是使用箭头函数便能解决

react
在这里插入图片描述
vue
在这里插入图片描述
React中this的丢失
首先来看看react,这是一个很普通的类组件写法:

class Demo extends React.Component{
    state = {
        someState:'state'
    }
    // ✅推荐
    arrowFunMethod = () => {
        console.log('THIS in arrow function:',this)
        this.setState({someState:'arrow state'})
    }
    // ❌需要处理this绑定
    ordinaryFunMethod(){
        console.log('THIS oridinary function:',this)
        this.setState({someState:'ordinary state'})
    }
    render(){
        return ( 
            <div>
                <h2>{this.state.someState}</h2>
                <button onClick={this.arrowFunMethod}>call arrow function</button>
                <button onClick={this.ordinaryFunMethod}>call ordinary function</button>
            </div>
        )
    }
}
ReactDOM.render(<Demo/>,document.getElementById('root'))

我在组件内我定义了两个方法:一个用箭头函数实现,另一个用普通函数。在调用时分别打印this,结果如下:
在这里插入图片描述
箭头函数中this正确指向了组件实例,但普通函数中却指向了undefined,为什么?

其实这是一个无关react的js特性,剥离react带来的心智负担,本质上,上面的代码不过是一个「类」,简化一下,就变成了这样 :

class ReactDemo {
    // ✅推荐
    arrowFunMethod = () => {
      console.log('THIS in arrow function:', this)
    }
    // ❌this指向丢失
    ordinaryFunMethod() {
      console.log('THIS in oridinary function:', this)
    }
  }
  const reactIns = new ReactDemo()
  let arrowFunWithoutCaller = reactIns.arrowFunMethod
  let ordinaryFunWithoutCaller = reactIns.ordinaryFunMethod
  arrowFunWithoutCaller()
  ordinaryFunWithoutCaller()

运行一下上面这段代码,会发现结果不出预料:在普通函数中this的指向也丢失了。
在这里插入图片描述
从react代码运行的角度来解释一下:

首先是事件触发时,回调函数的执行。回调函数不是像这样直接由实例调用:reactIns.ordinaryFunMethod(),而是像上面代码中的,做了一次“代理”,最后被调用时,找不到调用对象了:ordinaryFunWithoutCaller()。这时就出现了this指向undefined的情况。

但为什么使用箭头函数,this又可以正确指向组件实例呢?首先回顾一个简单的知识点:class是个语法糖,本质不过是个构造函数,把上面的代码用它最原始的样子写出来:

'use strict'
function ReactDemo() {
  // ✅推荐
  this.arrowFunMethod = () => {
    console.log('THIS in arrow function:', this)
  }
}
// ❌this指向丢失
ReactDemo.prototype.ordinaryFunMethod = function ordinaryFunMethod() {
  console.log('THIS in oridinary function:', this)
}
const reactIns = new ReactDemo()

可以看到:写成普通函数的方法,是被挂载到原型链上的;而使用箭头函数定义的方法,直接赋给了实例,变成了实例的一个属性,并且最重要的是:它是在「构造函数的作用域」被定义的。

我们知道,箭头函数没有自己的this,用到的时候只能根据作用域链去寻找最近的那个。放在这里,也就是构造函数这个作用域中的this——组件实例。

这样就可以解释为什么react组件中,箭头函数的this能正确指向组件实例。

vue中this的丢失
把上面的组件用vue来写一遍:

const Demo = Vue.createApp({
  data() {
      return {
          someState:'state',
      }
  },
  methods:{
      // ❌this指向丢失
      arrowFunMethod:()=>{
          console.log('THIS in arrow function:',this)
          this.someState = 'arrow state'
      },
      // ✅推荐
      ordinaryFunMethod(){
          console.log('THIS in oridinary function:',this)
          this.someState = 'ordinary state'
      }
  },
  template:`
  <div>
      <h2>{{this.someState}}</h2>
      <button @click='this.arrowFunMethod'>call arrow function</button>
      <button @click='this.ordinaryFunMethod'>call ordinary function</button>
  </div>`
})
Demo.mount('#root')

运行代码,会发现结果对调了:使用箭头函数反而导致了this指向丢失:this指向了undefined对象

在这里插入图片描述
这部分解释起来会稍微复杂一下,不过也只涉及一小块vue源码。主要的操作是vue对组件方法的处理,最核心的就三行,感兴趣的可以去看看完整代码:vue-github

function initMethods(vm: Component, methods: Object) {
  for (const key in methods) {
    vm[key] = bind(methods[key], vm)
  }
}

vue会把我们传入methods遍历,再一个个赋给到组建实例上,在这个过程就处理了this的绑定(bind(methods[key], vm)):把每一个方法中的this都绑定到组件实例上。

普通函数都有自己的this,所以绑定完后,被调用时都能正确指向组件实例。但箭头函数没有自己的this,便无从谈及修改,它只能去找父级作用域中的this。这个父级作用域是谁呢?是组件实例吗?我们知道作用域只有两种:全局作用域和函数作用域。回到我们写的vue代码,它本质就是一个对象(具体一点,是一个组件的配置对象,这个对象里面有data、mounted、methods等属性)也就是说,我们在一个对象里面去定义方法,因为对象不构成作用域,所以这些方法的父作用域都是全局作用域。箭头函数要去寻找this,就只能找到全局作用域中的this——window对象了。

上面说了这么多,总结一下:vue对传入的方法methods对象做了处理,在函数被调用前做了this指向的绑定,只有拥有this的普通函数才能被正确的绑定到组件实例上。而箭头函数则会导致this的指向丢失。

「为什么react中用箭头函数,vue中用普通函数」这是一个挺很有意思的问题,简单来说,这种差异是由于我们写的react是一个类,而vue是一个对象导致的。

在类中定义只有箭头函数才能根据作用域链找到组件实例;在对象中,只有拥有自身this的普通函数才能被修改this指向,被vue处理后绑定到组件实例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/336283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Myba tis基础2

接口代理方式代理开发方式介绍编写StudentMapper接口测试代理方式小结动态sql语句动态 SQL 之<**if>**动态 SQL 之<**foreach>**SQL片段抽取分页插件介绍分页插件的使用分页插件的参数获取小结MyBatis的多表操作多表模型介绍多表模型一对一操作多表模型一对多操作多…

Python创意作品说明怎么写,python创意编程作品集

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;Python创意作品说明怎么写&#xff0c;python创意编程作品集&#xff0c;现在让我们一起来看看吧&#xff01; 1、有哪些 Python 经典书籍 书名&#xff1a;深度学习入门 作者&#xff1a;[ 日&#xff3d; 斋藤康毅 …

《Linux运维实战:Centos7.6部署rabbitmq3.9.16镜像模式集群》

一、RabbitMQ集群的三种模式 RabbitMQ有三种模式&#xff1a;单一模式&#xff0c;普通集群模式&#xff0c;镜像集群模式。 单一模式&#xff1a;即单机情况不做集群&#xff0c;就单独运行一个rabbitmq而已。 普通集群模式&#xff1a;普通集群模式下&#xff0c;不同的节点…

TryHackMe-Carnage

Carnage 花了两天学了下wireshark 顺便看一下现在我的红队进程 由于ad在进攻性渗透测试当中已经早早收入囊中&#xff0c;这让我在红队进度中变快 现在&#xff0c;红队路径剩下的room应该都算是在整个path当中比较有难度的了&#xff0c;我不经意的查看了剩下的部分room&…

基于昇腾计算语言AscendCL开发AI推理应用

01 初始AscendCL AscendCL&#xff08;Ascend Computing Language&#xff0c;昇腾计算语言&#xff09;是昇腾计算开放编程框架&#xff0c;是对底层昇腾计算服务接口的封装&#xff0c;它提供运行时资源&#xff08;例如设备、内存等&#xff09;管理、模型加载与执行、算子…

c函数篇 入门 阶乘 ,素数(2019年)数列求和(2021年),完数,完全平方数,因子求和,x的y次方。

目录 1: 计算s1!2!3!......n! 2:素数问题2019 3:编写程序判断一个数是不是完数 4:编写函数 求x的y次方 完成pow(x,y)的功能 5:输出1到1000内所有完全平方数 6:求因子之和 数列求和 1: 计算s1!2!3!......n! #include<stdio.h> long fac(int n) {int i;long s1;for…

龙智宣布与Incredibuild建立战略合作伙伴关系

近日&#xff0c;龙智宣布与领先的加速编译软件提供商Incredibuild建立战略合作伙伴关系。 Incredibuild是一款加速编译工具。凭借其独特的进程虚拟化技术&#xff08;Vritualized Distributed Processing™&#xff09;&#xff0c;使用户能够轻松地加速代码构建、测试和许多…

Windows10下安装git

文章目录安装环境&#xff1a;Windows10 64bit官网下载&#xff1a;https://git-scm.com/download/win国内下载源&#xff1a;https://npm.taobao.org/mirrors/git-for-windows/ 从官网下载Git安装包&#xff0c;双击下载后的安装包Git-2.32.0-64-bit.exe,开始安装 选择HTTPS…

java面试题(十八)spring MVC

3.1 什么是MVC&#xff1f; 参考答案 MVC是一种设计模式&#xff0c;在这种模式下软件被分为三层&#xff0c;即Model&#xff08;模型&#xff09;、View&#xff08;视图&#xff09;、Controller&#xff08;控制器&#xff09;。Model代表的是数据&#xff0c;View代表的…

【解决方案】老旧小区升级改造,视频智能化能力如何提升居民安全感?

一、需求背景 随着我国社会经济的快速发展与进步&#xff0c;城市宜居程度成为城市发展的重要指标&#xff0c;城市的发展面临着更新、改造和宜居建设等。一方面&#xff0c;社区居民对生活的环境提出了更高的要求&#xff1b;另一方面&#xff0c;将“智慧城市”的概念引入社…

[MySQL教程①] - MySQL的安装

目录 ❤ Windows下安装MySQL ❤ 下载mysql installer安装 ❤ 下载zip安装包安装 现在作为服务器操作系统的一般有三种&#xff0c;Windows Server&#xff0c;Linux&#xff0c;Unix&#xff0c;在这里我们只介绍在windows下和linux下安装mysql&#xff0c;Unix下安装应该…

03 AC-AC变换器(ACAC Converter)简介

文章目录0、 杂记1、AC-AC变换器概述2、交流调压电路A 相控交流调压3、交流调压电路B 三相相控交流电压4、交流调压电路C 斩控交流电压5、交流调功电路6、交-交变频电路A 周波变换器7、交-交变频电路B 矩阵变换器8、AC-AC变换器总结0、 杂记 在复杂的周期性振荡中&#xff0c;…

百度贴吧发帖软件如何发布?

百度贴吧发帖软件如何发布&#xff1f;贴吧软件发帖顶帖视频教学&#xff0c;防删图技术视频教学#贴吧发帖#贴吧顶帖 大家好&#xff0c;今天给大家讲一下一个贴软件发电机顶帖的视频教学。先给大家讲一下软件一个发帖。今天我们用的一个软件叫做神机。神机我们现在看到的软件…

RESTful API 为何成为顶流 API 架构风格?

作者孙毅&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Committer 万物互联的世界充满着各式各样的 API &#xff0c;如何统筹规范 API 至关重要。RESTful API 是目前世界上最流行的 API 架构风格之一&#xff0c;它可以帮助你实现客户端与服务端关注点分离&#x…

Vue3 企业级优雅实战 - 组件库框架 - 12 发布开源组件库

前面使用了 11 篇文章分享基于 vue3 、Monorepo 的组件库工程完整四件套&#xff08;组件库、文档、example、cli&#xff09;的开发、构建及组件库的发布。本文属于这 11 篇文章的扩展 —— 如何发布到 GitHub 上以及如何快速利用 GitHub 发布组件库文档。这样优雅哥的《组件库…

Springboot862大学生社团管理系统

后台两大功能模块&#xff0c; (1)管理员&#xff1a;个人中心、学校管理、学院管理、年级管理、班级管理、社长管理、学生管理、社团类型管理、社团信息管理、社团成员管理、退团记录管理、社团活动管理、活动报名管理、退出活动管理、社团事务管理、系统管理。 (2)社长&#…

PyTorch学习笔记:nn.SmoothL1Loss——平滑L1损失

PyTorch学习笔记&#xff1a;nn.SmoothL1Loss——平滑L1损失 torch.nn.SmoothL1Loss(size_averageNone, reduceNone, reductionmean, beta1.0)功能&#xff1a;创建一个平滑后的L1L_1L1​损失函数&#xff0c;即Smooth L1&#xff1a; l(x,y)L{l1,…,lN}Tl(x,y)L\{l_1,\dots,l…

【Python爬虫实战案例】采集城市桌游商家数据信息,做可视化演示

前言 这里容我罗嗦几句 &#x1f617; 这个时间&#xff0c;我想大学生应该都回学校了吧&#xff0c;嘿嘿 现在应该蛮忙的&#xff0c;有些的还要准备开学考&#xff0c;临近毕业的朋友&#xff0c;也快要因为工作而烦恼了&#xff0c;但是&#xff01;&#xff01; 咱也是…

新版国家标准GB/T 28181—2022将于2023年7月1日正式实施,与GB/T 28181—2016差别有哪些?

新版国家标准GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》已于2022年12月30日发布&#xff0c;将于2023年7月1日正式实施。与GB/T 28181—2016相比&#xff0c;除结构调整和编辑性改动外&#xff0c;主要技术变化如下。——更改了标准范围&#xf…

排序:堆排序

一、树与二叉树 二、二叉树 1.二叉树&#xff1a;度不超过2的树&#xff08;度&#xff1a;树的分支&#xff09;&#xff0c;每个节点最多有两个孩子节点&#xff0c;两个孩子节点被区分为左孩子节点和右孩子节点。 2.满二叉树&#xff1a;一个二叉树&#xff0c;如果每一个层…