(自制翻译)如何处理在vue中this报错undefined
原文:https://michaelnthiessen.com/this-is-undefined/
当你开心地在编程,惊叹于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、reduce
- vue组件里的各种地方
举几个栗子:
// 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);1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » (自制翻译)如何处理在vue中this报错undefined