专栏首页全栈开发之路(自制翻译)如何解决在vue中this报错undefined

(自制翻译)如何解决在vue中this报错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 data
fetch('/getSomeData').then((data) => {
  this.data = data;
});

// Functional methods
const 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 scope
window.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);

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JS执行上下文/作用域/闭包

    2)一般来说内部能访问外部,外部不能访问内部。 那么怎么让外部也能访问内部? —— return

    杨肆月
  • Bootstrap学习笔记

    2、col有四个类分别适应不同设备 xs——extra small sm——small md——medium ...

    杨肆月
  • 2019-08-23

    1、console.log(["1", "3", "10"].map(parseInt))输出什么 答案:[ 1, NaN, 2 ] 解答:

    杨肆月
  • 论普通函数和箭头函数的区别以及箭头函数的注意事项、不适用场景

    箭头函数是ES6的API,相信很多人都知道,因为其语法上相对于普通函数更简洁,深受大家的喜爱。就是这种我们日常开发中一直在使用的API,大部分同学却对它的了解程...

    OBKoro1
  • 前端测试题: 关于箭头函数的描述,错误的是?

    箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

    舒克
  • 如何修复Vue中的 “this is undefined” 问题

    别担心,不只有你一个人,我也经常遇到这个问题很多次,接下我们一起来看看如何解决这个问题。

    前端小智@大迁世界
  • ES6的箭头函数的详细介绍

    如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。

    Javanx
  • 深入理解JavaScript闭包之什么是闭包

    在看本篇文章之前,可以先看一下之前的文章 深入理解JavaScript 执行上下文 和 深入理解JavaScript作用域,理解执行上下文和作用域对理解闭包有很...

    木子星兮
  • Python基础——1基础

    a=[1,2,32,’xue’,’sun’,[‘又一个list’,’haha’,1,2,52],True]

    py3study
  • 【react】关于react框架使用的一些细节要点的思考

    ( _(:3 」∠)_给云友们提个建议,无论是API文档还是书籍,一定要多看几遍!特别是隔一段时间后,会有意想不到的收获的) 这篇文章主要是写关于学习react...

    外婆的彭湖湾

扫码关注云+社区

领取腾讯云代金券