侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

如何解决在vue中this报错undefined

前端  /  管理员 发布于 6年前   792

当你开心地在编程,惊叹于vue的神奇,这时你却遇到这样的情况:
你的vue应用无法正常工作,你收到的报错是:this is undefined

产生问题的原因是你混合使用了普通函数和箭头函数。我猜你肯定用了一个箭头函数。如果你把这个箭头函数替换成普通函数,也许能解决上面你遇到的问题。

接下来让我们深入原理来了解为什么会产生这个问题。
毕竟,知识是强大的,如果你知道了问题的原因,你将能够避免更多问题并节省时间。

还有一些其他场景下会让你遇到this is undefined的报错:

当你使用fetch或axios请求数据时
当你使用lodash库或underscore库时

我接下来也会提到这些场景并告诉你如何解决


理解两种类型的函数

在JavaScript里我们可以使用两种不同的函数。它们运行方式几乎是一样的,除了它们处理变量this的方法有所不同。

普通函数

一个普通函数有许多定义方式
第一种方式在vue组件中不太常见,因为写起来股票于冗长:

methods: {  regularFunction: function() {    // Do some stuff  }}

第二种方式的写法简短且通用

methods: {  shorthandFunction() {    // Do some stuff  }}

在一个普通函数中,this归属于函数的“拥有者”。由于我们是在vue组件里定义的,那么this归属于vue组件。接下来我将解释this的作用域。

大多数情况下你在vue里最好使用普通函数,特别是当你构建:

methods
computed props
watched props

普通函数通常是你所需要的,而箭头函数用起来更便利。


箭头函数

箭头函数书写起来更简略更快捷,并能为我们获得更多人气。但是它变得不那么好了当我们在一个对象里定义方法时,比如当我们编写vue组件时。
以下是箭头函数在vue组件里的写法:

methods: {  arrowFunction: () => {    // Do some stuff  }}

普通函数和箭头函数真正的差异产生于它们处理this的方式。
在一个箭头函数里,this并不归属于函数的拥有者。
箭头函数的作用域被称为词法作用域(或静态作用域lexical scoping)。我们将深究其中的原理,但首先我们要明白在箭头函数中,this是去函数定义时的环境中查询的。
如果你想在vue组件中的箭头函数内部去调用this,你将收到报错,因为this并不存在

data() {  return {    text: 'This is a message',  };},methods: {  arrowFunction: () => {    console.log(this.text);  // ERROR! this is undefined  }}

总而言之,避免在vue组件中使用箭头函数,这将会避免很多问题的发生。
当然,也有适合使用箭头函数的场景。但前提是你并没有引用this:

computed: {  location: () => window.location,}

既然我们了解了函数的两种主要类型,那么我们该如何在正确的场景下使用它们呢?


匿名函数

当你仅仅是想快速构建一个函数且并不需要调用它时,使用匿名函数是非常适合的。这类函数之所以被称为匿名函数,是因为它们不需要赋予函数名和参数值。
以下场景适合使用匿名函数:

使用fetch或axios请求数据使用函数型方法,比如filter、map、reducevue组件里的各种地方

举几个栗子:

// Fetching datafetch('/getSomeData').then((data) => {  this.data = data;});// Functional methodsconst array = [1, 2, 3, 4, 5];const filtered = array.filter(number => number > 3);const mapped = array.map(number => number * 2);const reduced = array.reduce((prev, next) => prev + next);

正如你在例子中看到的,大部分情况下我们使用匿名函数时也会用到箭头函数。通常我们使用箭头函数是由于:

简练精巧的语法增强代码可读性this在上下文中被读取

在vue的methods里使用匿名函数,箭头函数也能发挥强大的作用。
桥豆麻袋,难道我们已经搞清箭头函数在引用this没起作用的原因了?
emmmm下面才切入重点。
当我们在普通函数里使用箭头函数时,普通函数会设置this作为我们的vue组件,这样箭头函数就能正常使用this了
看下面这个例子:

data() {  return {    match: 'This is a message',  };},computed: {  filteredMessages(messages) {    console.log(this); // Our Vue component        const filteredMessages = messages.filter(      // References our Vue Component      (message) => message.includes(this.match)    );        return filteredMessages;  }}

filter之所以能正常引用this.match,是因为箭头函数和mehod里的filteredMessages使用了同一上下文。正因为这个method使用的是普通函数(而不是箭头函数),它在vue里创建了自己的上下文。
接下来继续拓展当你使用axios或fetch请求数据时该怎么解决箭头函数的问题。


使用正确的函数来请求数据

当你使用fetch或axios来异步请求数据时,你肯定也会用到promise。Promises非常喜欢使用匿名箭头函数,并且也让this的使用更加简单。
如果你要在你的组件里请求数据,你一般会这么做:

export default {  data() {    return {      dataFromServer: undefined,    };  },  methods: {    fetchData() {      fetch('/dataEndpoint')        .then(data => {          this.dataFromServer = data;        })        .catch(err => console.error(err));    }  }};

可以看到我们再vue组件的methods里先是使用了普通函数,然后在promise里使用了匿名箭头函数

.then(data => {  this.dataFromServer = data;})

在普通函数fetchData()的作用域里,this被设置成vue组件。由于箭头函数使用的是父级作用域作为自己的作用域,所以箭头函数也把this当做是vue组件了。
这样就允许我们通过this去引用vue组件并更新dataFromServer


使用Lodash库或Underscore库

(没用过这两个库,不翻译了)


什么是lexical scoping(静态作用域)

正如我们之前提到的,普通函数和箭头函数存在这样一个差异:静态作用域。
首先,作用域出现在变量存在的地方。在JavaScript中,window变量有全局作用域——在任何地方都可以被调用。大多数变量只在被定义的函数里、class类中、模块里会生效。
其次,“静态”这个词意味着代码块里的作用域。一些程序语言仅仅是在运行程序时才定义作用域。这将导致很多问题,所以大部分语言使用的是静态作用域。
箭头函数使用静态作用域,但普通函数并不是。
静态作用域的奇妙之处在于它在函数中对this的影响。对于箭头函数,this引用的是外层作用域的this。而普通函数引用this就很奇怪,这也是为什么箭头函数被更多人推荐使用。


在函数中作用域是如何工作的
// This variable is in the window's scopewindow.value = 'Bound to the window';const object = {  // This variable is in the object's scope  value: 'Bound to the object',  arrowFunction: () => {    // The arrow function uses the window's scope for `this`    console.log(this.value); // 'Bound to the window'  },  regularFunction() {    // The regular function uses the object's scope for `this`    console.log(this.value);  // 'Bound to the object'  }};

现在你知道作用域在函数里如何工作了吧。
但也有办法通过重写改变这种行为。


绑定另一个函数的作用域
const boundFunction = unboundFunction.bind(this);


  • 上一条:
    使用ES6让你的React代码提升到一个新档次
    下一条:
    vue axios不缓存get请求(防止返回304不更新数据)
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客