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

作者:Michael Thiessen

译者:前端小智

来源:techalyst

点赞再看,养成习惯

本文 GitHub https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。

当我们使用 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组件时具有更大的灵活性,更轻松地重用方法。当然,可读性相对差点,应该尽量避免太频繁地使用它。

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

交流

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

1460000020353567?w=800&h=400

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[如何修复Vue中的 “this is undefined” 问题]http://www.zyiz.net/tech/detail-119098.html

在使用Vue和Three.js结合ThreeBSP库时,如果遇到"parent is undefined"的错误,通常是因为在Vue组件的生命周期钩子中访问Three.js对象时,Three.js的场景或对象尚未初始化完成。以下是一些可能的解决方案: 1. **确保初始化顺序**: 确保在Vue组件的`mounted`钩子中初始化Three.js对象,而不是在`created`钩子中。`mounted`钩子表示组件的DOM已经挂载完成,此时可以安全地访问和操作DOM相关的对象。 2. **使用生命周期钩子**: 使用Vue的生命周期钩子来确保在操作Three.js对象之前,所有必要的对象已经初始化完成。例如,可以在`mounted`钩子中初始化Three.js场景、相机和渲染器。 3. **检查对象引用**: 确保在操作Three.js对象之前,所有引用都是有效的。例如,在使用ThreeBSP进行布尔运算之前,确保所有几何体和材质都已经正确创建和引用。 以下是一个简单的示例代码,展示了如何在Vue组件中正确初始化Three.js和ThreeBSP: ```javascript <template> <div ref="rendererContainer"></div> </template> <script> import * as THREE from 'three'; import ThreeBSP from 'three-js-csg'; export default { name: 'ThreeJsComponent', data() { return { scene: null, camera: null, renderer: null, geometry: null, material: null, mesh: null, }; }, mounted() { this.init(); this.animate(); }, methods: { init() { this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.renderer = new THREE.WebGLRenderer(); this.renderer.setSize(window.innerWidth, window.innerHeight); this.$refs.rendererContainer.appendChild(this.renderer.domElement); this.geometry = new THREE.BoxGeometry(1, 1, 1); this.material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); this.mesh = new THREE.Mesh(this.geometry, this.material); this.scene.add(this.mesh); this.camera.position.z = 5; }, animate() { requestAnimationFrame(this.animate); this.renderer.render(this.scene, this.camera); }, }, }; </script> <style> div { width: 100%; height: 100%; } </style> ``` 在这个示例中,我们确保在`mounted`钩子中初始化Three.js对象,并在`animate`方法中渲染场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值