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

时间: 2020-02-15阅读: 1047标签: this

当我们使用 vue 在愉快的开发项目的时候,突然报了一个错误:

this is undefined

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

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

我们再深入一点,试着理解为什么会这样。

毕竟,知识就是力量,如果知道造成问题的原因,那么我们将来可以避免很多挫败感和时间浪费。

还有一些其它原因可能也会出现此类错误。

  • 使用 fetch 或 axios 获取数据
  • 使用像 lodash 或 underscore 这类的库


理解两种主要的函数类型

js 中,我们有两种不同的函数。它们以几乎相同的方式运作,除了它们处理变量的方式不同。

这给新旧JavaScript开发人员带来了很多困惑,但是当我们弄懂这个问题时,就很好会有这个困惑。


常规函数

常规函数可以用几种不同的方式定义。

第一种方法在 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,
}

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


匿名函数

当我们只需要创建一个函数而不需要从其他任何地方调用它时,匿名函数非常有用。

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

  • 使用 axios 或 fetch 访存数据
  • 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方法中,箭头函数也可以作为匿名函数使用。

等等,我们不是刚发现当我们试图访问 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实例。

让我们进一步讨论如何使用axios或fetch来获取数据。


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

如果正在使用fetch或axios获取异步数据,最好使用 Promise。Promise喜欢匿名箭头函数,它们也使处理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。

但是,如果需要将函数传递帮助库,比如lodash或underscore,该怎么办呢


与 Lodash 或 Underscore 一起使用

假设我们的Vue组件上有一个要使用Lodash或Underscore方法。如何防止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组件时具有更大的灵活性,更轻松地重用方法。当然,可读性相对差点,应该尽量避免太频繁地使用它。

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


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/8202

Js函数作用域、执行环境(this)、call、apply、bind 的用法

函数作用域:在 JavaScript 中,作用域为可访问变量,对象,函数的集合。JavaScript 函数作用域: 作用域在函数内修改。this对象是在运行时基于函数的执行环境绑定的。

js中this的详细解释,JavaScript中this绑定规则【你不知道的JavaScript】

this的绑定过程之前的调用栈 和 调用位置,this绑定规则:1、默认模式,2、隐式绑定,3、显式绑定,4、new绑定

JS中this的几种情况

给元素的某个事件行为绑定方法,事件触发,方法执行,此时方法中的this一般都是当前元素本身:普通函数执行,它里边的this是谁,取决于方法执行前面是否有“.”,有的话,“.”前面是谁this就是谁,没有的话并且是在非严格模式下this就是window,严格模式下是undefined:

在回调函数中如何正确的访问this变量

this(又名“上下文”)是每个功能内的特殊关键字和它的值仅取决于如何调用函数,而不是如何/何时/何它被定义。它不像其他变量那样受词法作用域的影响

解读Javascript中的this机制,别再为了 this 发愁了

JavaScript中有很多令人困惑的地方,或者叫做机制。但是,就是这些东西让JavaScript显得那么美好而与众不同。比方说函数也是对象、闭包、原型链继承等等,而这其中就包括颇让人费解的this机制。

JavaScript 中的 this 全面解析

this的指向问题应该是让每一个前端er都头疼的问题,我也一样,曾经遇到甚至都是一顿乱猜。最近在研读一些书籍如《你不知道的JavaScript》和《JavaScript语言精粹与编程实践》,让我对this的问题豁然开朗

JavaScript中this的运行机制及爬坑指南

在 JavaScript 中,this 这个特殊的变量是相对比较复杂的,因为 this 不仅仅用在面向对象环境中,在其他任何地方也是可用的。 本篇博文中会解释 this 是如何工作的以及使用中可能导致问题的地方,最后奉上最佳实践。

这 7 道关于 this 的面试题,你能答对几个?

在 JavaScript 中, this 是函数调用上下文。正是由于 this 的行为很复杂,所以在 JavaScript 面试中,总是会问到有关 this 的问题。

浅析js中的this

this是一个对象,一般存在于函数中,表示当前函数的执行上下文;值得一提的是,当函数在执行后,this才有绑定的对象,函数未执行时,this没有内容,接下来我们看看在不同场景下的this的指向

Js中call/apply/bind方法函数的原生实现

在JavaScript中,函数中this的指向往往在调用时才可确定,而JavaScript提供了call/apply/bind方法让我们得以显示绑定函数的this指向。它们的第一个参数是一个对象,它们会把这个对象绑定到调用他们的函数内的this

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!