如何解决在vue中this报错undefined入门教程_undefined零基础入门

当你开心地在编程,惊叹于vue的神奇,这时你却遇到这样的情况:你的vue应用无法正常工作,你收到的报错是:this is undefined产生问题的原因是你混合使用了普通函数和箭头函数。我猜你肯定用了一个箭头函数。如果你把这个箭头函数替换成普通函数,也许能解决上面你遇到的问题。接下来让我们深入原理来了解为什么会产生这个问题。毕竟,知识是强大的,如果你知道了

如何解决在vue中this报错undefined入门教程

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

如何解决在vue中this报错undefined入门教程_undefined零基础入门

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

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

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

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

理解两种类型的函数

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

普通函数

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

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

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

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

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

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

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

箭头函数

箭头函数书写起来更简略更快捷,并能为我们获得更多人气。但是它变得不那么好了当我们在一个对象里定义方法时,比如当我们编写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,
}

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

匿名函数

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

举几个栗子:

// 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);

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

在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);
海计划公众号
(1)
上一篇 2020/04/03 19:42
下一篇 2020/04/03 19:42

您可能感兴趣的内容

  • Vue.js-计算属性和class与style绑定攻略教程_属性使用攻略

    计算属性
    所有的计算属性都以函数的形式写在Vue实例中的computed选项内,最终返回计算后的结果。
    计算属性的用法
    在一个计算属性中可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果即可。
    计算属性还可以依赖多个Vue实例的数据,只要其中任一数据变化,计算属性就会重新执行,视图也会更新。
    每一个计算属性都包含一个getter和一个set

    2020/03/30
  • FreeMarker网页静态化使用帮助_网页基础指南

    网页静态化解决方案在实际开发中运用比较多,例如新闻网站,门户网站中的新闻频道或者是文章类的频道。网页静态化技术和缓存技术的共同点都是为了减轻数据库的访问压力,但是具体的应用场景不同,缓存比较适合小规模的数据,而网页静态化比较适合大规模且相对变化不太频繁 的数据。另外网页静态化还有利于SEO。另外我们如果将网页以纯静态化的形式展现,就可以使用Nginx这样的高

    2020/03/29
  • Web 堆栈选择指南:JAMStack vs MEAN vs LAMP小白知识_指南小白知识

    开发人员需要做的决策有很多。当 Web 应用程序的需求确定下来之后,就该选择效率最高的 Web 技术栈了。Web 技术栈是用于创建 Web 应用程序的技术工具集。一套 Web 技术栈由 OS(操作系统)、Web 服务器、数据库软件以及编程语言(通常前端和后端都需要自己的语言)组成。一些常见的编程语言 / 框架包括 PHP、JavaScript、Node.js

    2020/03/23
  • TypeScript 设计模式之单例模式小白帮助_模式基础知识入门

    单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的 window 对象等。单例模式用于保证一个类仅有一个实例,并提供一个访问它的全局访问点。二、优缺点优点由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。由于单例模式只生成一个

    2020/03/20
  • React Native 使用 react-native-webview 渲染 HTML攻略教程_渲染使用说明

    在 App 中,渲染 HTML 是一个非常常见的功能,有可能是直接渲染 HTML 字符串或者是通过 URL 渲染远程 HTML页面。React Native 提供了一个 WebView 组件以供我们实现 HTML 的渲染。早先 WebView 是在 React Native 核心包中,后来为了减小 React Native 核心包的体积,便将其单独提出到re

    2020/03/23
  • CanJS小白攻略_Web前端应用框架

    CanJS小白攻略 官方网址:https://canjs.com/ GitHub:https://github.com/canjs/canjs 简介描述:Web前端应用框架 Can…

    2020/03/06
  • VSCode调试网页JavaScript代码基础知识教程_调试小白入门

    一、调试准备Windows10 64bitsIDE:Visual Studio Code1.28.2安装插件:Chrome(安装方法:Debug -> Install Additional Debuggers… -> Debugger for Chrome,重新启动vscode即可。)二、调试配置首先该插件运行需要安装有本地服务器,其次有两种配置方式,分

    2020/04/03
  • interact.js使用说明_用于拖放,调整大小Js插件

    interact.js使用说明 官方网址:http://interactjs.io/ GitHub:https://github.com/taye/interact.js 简介描述…

    2020/03/06
  • typescript和javascript的区别是什么菜鸟教程下载_区别小白入门

    TypeScript和JavaScript是目前项目开发中较为流行的两种脚本语言,我们已经熟知TypeScript是JavaScript的一个超集,但是TypeScript与JavaScript之间有什么样的区别呢?JavaScript 和 TypeScript 的概要介绍JavaScriptJavaScript 是一种轻量级的解释性脚本语言,可嵌入到 HT

    2020/03/31
  • 不同浏览器的内核小白攻略_浏览器基础教程

    什么是浏览器内核?网页上所用到的语言有:html, css, JavaScript等,其中,前两者通常决定了该页面长什么样,它们是可以说都是约定的规范。不同的浏览器在获取到某页面的代码文件后,负责根据这套规范将代码渲染出来呈现给用户,浏览器内核所做的就是这个渲染工作。因此,浏览器内核,也被称为排版引擎(layout engine)、渲染引擎(renderin

    2020/03/26
  • JS使用textarea模拟post提交表单菜鸟教程下载_表单菜鸟教程下载

    textarea 标签textarea代表HTML表单多行输入域textarea标签是成对出现的,以结束属性:cols — 多行输入域的列数rows — 多行输入域的行数accesskey — 表单的快捷键访问方式disabled — 输入域无法获得焦点,无法选择,以灰色显示,在表单中不起任何作用re

    2020/03/24
  • Js算法:计算两数之和使用指南_算法使用指南

    题目描述:给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例给定 nums = [2,4,5,6], target = 9
    因为 nums[1]

    2020/03/29
  • js事件概念和事件监听小白指南_事件指南教程

    事件的概念JavaScript使我们有能力创建动态页面,网页中的每个元素都可以产生某些可以触发JavaScript函数的事件。我们可以认为事件是可以被JavaScript侦测到的一种行为。使用返回值改变HTML元素的默认行为HTML元素大都包含了自己的默认行为,例如:超链接、提交按钮等。我们可以通过在绑定事件中加上return false来阻止它的默认行为1

    2020/03/29
  • css的继承性小白入门_继承入门基础知识

    css 的继承性是什么?在面向对象语言都会存在继承的概念,在面向对象语言中,继承的特点:继承了父类的属性和方法。
    那么我们现在主要研究css,css就是在设置属性的。不会牵扯到方法的层面。css的继承:就是给父级设置一些属性,子级继承了父级的该属性,这就是我们的css中的继承。 官方解释,继承是一种规则,它允许样式不仅应用于特定的html标签元素,而且应用于

    2020/03/30
  • jstree入门攻略_基于jQuery跨浏览器树控件,功能强大树控件

    jstree入门攻略 官方网址:http://jstree.com GitHub:https://github.com/vakata/jstree 简介描述:基于jQuery跨浏览…

    2020/03/06
  • 分享 10 个超实用的 Chrome 扩展入门基础教程_插件小白常识

    分享 10 个超实用的 Chrome 扩展入门基础教程 1. CSSViewer 这个工具在识别和显示元素的CSS属性方面很有用。它包括一个浮动窗口,您可以把鼠标悬停在页面上任一元…

    2020/03/19