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

做者:Michael Thiessen
译者:前端小智
来源:techalyst
点赞再看,养成习惯

本文 GitHub https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了不少个人文档,和教程资料。欢迎Star和完善,你们面试能够参照考点复习,但愿咱们一块儿有点东西。javascript


当咱们使用 Vue 在愉快的开发项目的时候,忽然报了一个错误:前端

this is undefined

别担忧,不仅有你一我的,我也常常遇到这个问题不少次,接下咱们一块儿来看看如何解决这个问题。vue

一个可能的缘由是混淆了常规函数和箭头函数的用法,若是你遇到这个问题,我猜你用的是箭头函数。若是用常规函数替换箭头函数,它可能会为你修复这个问题。java

咱们再深刻一点,试着理解为何会这样。ios

毕竟,知识就是力量,若是知道形成问题的缘由,那么咱们未来能够避免不少挫败感和时间浪费。git

还有一些其它缘由可能也会出现此类错误。github

  • 使用 fetchaxios 获取数据
  • 使用像 lodashunderscore 这类的库

理解两种主要的函数类型

在 JS 中,咱们有两种不一样的函数。它们以几乎相同的方式运做,除了它们处理变量的方式不一样。面试

这给新旧Javascript开发人员带来了不少困惑,可是当咱们弄懂这个问题时,就很好会有这个困惑。编程

常规函数

常规函数能够用几种不一样的方式定义。axios

第一种方法在 Vue 组件中较不常见,由于写出来要更长一些:

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

第二种方法是简写方式,咱们也常用:

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

在像这样的常规函数中,this将引用函数的“全部者”。由于咱们是在Vue组件上定义它的,因此this指的是Vue组件。

在大多数状况下,咱们应该在 Vue 中使用常规函数,特别是在建立时

  • methods
  • computed props
  • watched props

虽然常规函数一般是咱们所须要的,可是箭头函数也很是方便。

箭头函数

箭头函数能够更短,更快的编写,所以最近得到了普遍的欢迎。可是,它们在对象上定义方法时并无太大的不一样,就像咱们在编写Vue组件时所作的那样。

这是他们在Vue组件上的样子:

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

在处理 this 问题时,真正的差别开始发挥做用。

箭头函数采用词法做用域,意味着箭头函数从它的上下文中获取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,
}

如今咱们知道两种主要的函数类型,如何正确使用它们?

匿名函数

当咱们只须要建立一个函数而不须要从其余任何地方调用它时,匿名函数很是有用。

下面是使用匿名函数的一些场景

  • 使用 axiosfetch 访存数据
  • filtermapreduce等函数方法
  • 在 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方法中,箭头函数也能够做为匿名函数使用。

等等,咱们不是刚发现当咱们试图访问 this 时,箭头函数不起做用吗?

这就是区别所在。

当咱们在常规函数或简写函数中使用箭头函数时,常规函数将this设置为咱们的Vue组件,而箭头函数则不同。

来个例子:

data() {
  return {
    match: 'This is a message',
  };
},
computed: {
  filteredMessages(messages) {
    console.log(this); // Vue
    
    const filteredMessages = messages.filter(
      // 引用咱们的Vue组件
      (message) => message.includes(this.match)
    );
    
    return filteredMessages;
  }
}

filter方法能够访问this.match,由于箭头函数使用的方法与filteredMessages方法使用的上下文相同。 因为此方法是常规函数(而不是箭头函数),所以将其自身的上下文设置为Vue实例。

让咱们进一步讨论如何使用axiosfetch来获取数据。

在获取数据时使用正确的函数

若是正在使用fetchaxios获取异步数据,最好使用 PromisePromise喜欢匿名箭头函数,它们也使处理this问题变得容易得多。

若是你正在获取一些数据并想在你的组件上设置它,这是你应该作的正确的方式:

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

请注意,咱们如何在 Vue 组件上使用常规函数做为方法,而后在 Promise 内部使用匿名箭头函数

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

fetchData()做用域内,咱们将this设置为Vue组件,由于它是一个常规函数。因为箭头函数使用外部做用域做为它们本身的做用域,所以箭头函数也将this设置为咱们的Vue组件。

这容许咱们经过this访问 Vue 组件并更新dataFromServer

可是,若是须要将函数传递帮助库,好比lodashunderscore,该怎么办呢

与 Lodash 或 Underscore 一块儿使用

假设咱们的Vue组件上有一个要使用LodashUnderscore方法。如何防止this is undefine的错误。

若是你用过 React ,你可能见过相似的东西。

这是咱们用Vue作的。

created() {
  this.methodToDebounce = _.debounce(this.methodToDebounce, 500);
},
methods: {
  methodToDebounce() {
    // Do some things here
  }
}

就是这样!

咱们要作的就是获取函数,将其包装在debounce函数中,而后返回一个内建了debounce的新函数。如今,当咱们在Vue组件上调用this.methodToDebounce()时,咱们将调用debounced版本。

什么是词法做用域

如前所述,常规函数和箭头函数之间存在差别的主要缘由与词法做用域有关。来分析一下它的含义。

首先,做用域是程序中存在变量的任何区域。在Javascript中,window 变量具备全局做用域,它在任何地方均可用。尽管大多数变量被限制在定义它们的函数、它们所属的类或模块中。

其次,单词“词法”仅仅意味着做用域由你如何编写代码决定。某些编程语言只在程序运行时才肯定做用域内的内容。这可能会让人很困惑,因此大多数语言都只使用词法做用域。

箭头函数使用词法做用域,而常规函数和简写函数不使用。

这里最棘手的部分是词法做用域如何在函数中影响 this。对于箭头函数,this与外部做用域的this绑定在一块儿。常规函数的this绑定方式有些奇怪,这就是引入箭头函数的缘由,也是为何大多数人尽量多地使用箭头函数的缘由。

做用域如何在函数中工做

下面是一些示例,它们演示了做用域如何在这两种函数类型之间以不一样的方式工做

// 此变量在 window 做用域内
window.value = 'Bound to the window';

const object = {
  // 此变量在 object 做用域内
  value: 'Bound to the object',
  arrowFunction: () => {
    console.log(this.value); // 'Bound to the window'
  },
  regularFunction() {
    console.log(this.value);  // 'Bound to the object'
  }
};

将做用域绑定到函数上

咱们可使用 bind 方法来改变 this 的绑定

const boundFunction = unboundFunction.bind(this);

这使咱们在编写Vue组件时具备更大的灵活性,更轻松地重用方法。固然,可读性相对差点,应该尽可能避免太频繁地使用它。


代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug

原文:
https://www.techalyst.com/pos...


交流

文章每周持续更新,能够微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,整理了不少个人文档,欢迎Star和完善,你们面试能够参照考点复习,另外关注公众号,后台回复福利,便可看到福利,你懂的。

相关文章
相关标签/搜索