在Vue中,回调函数里的this指向出错,是JavaScript自身this动态绑定机制造成的,并非Vue的问题。下面详细解释具体缘由以及解决办法:
this的绑定规则在JavaScript中,函数里this的指向由函数的调用方式决定,而非定义位置。主要有以下几种绑定情况:
this指向window对象。foo()这种普通函数调用,this指向全局对象(非严格模式)或者undefined(严格模式)。obj.foo(),this指向调用该方法的对象obj。new调用函数时,this指向新创建的实例。call()、apply()或者bind()方法,可以手动指定this的指向。this,它会捕获其所在上下文的this值。在Vue组件中,虽然组件方法的this默认指向组件实例(遵循方法调用的规则,例如this.foo()中的this指向组件),但在以下这些回调场景中,this的指向会发生改变:
export default {
data() {
return {
message: 'Hello'
}
},
mounted() {
setTimeout(function() {
console.log(this.message); // 错误!这里的this指向window或undefined
}, 1000);
}
}原因:setTimeout的回调函数是作为普通函数被调用的(window.setTimeout()),所以this指向全局对象或者undefined。
fetchData() {
axios.get('/api/data')
.then(function(response) {
this.data = response.data; // 错误!this指向回调函数自身
});
}原因:then方法的回调同样是普通函数,this没有指向Vue组件。
mounted() {
document.addEventListener('click', function() {
this.handleClick(); // 错误!this指向document
});
}原因:DOM事件监听器的回调函数里,this指向触发事件的DOM元素。
this指向错误的方法箭头函数会捕获其定义时的上下文的this值,这样就能保证在回调中使用的this是Vue组件实例。
mounted() {
setTimeout(() => {
this.message = 'Updated'; // 正确!this指向Vue组件
}, 1000);
}this在回调函数外部把this保存到一个变量,然后在回调中使用这个变量。
mounted() {
const self = this; // 保存Vue组件的this
setTimeout(function() {
self.message = 'Updated'; // 使用保存的self
}, 1000);
}bind()方法通过bind()方法强制绑定回调函数的this。
mounted() {
document.addEventListener('click', function() {
this.handleClick(); // 现在this指向Vue组件
}.bind(this)); // 绑定this
}虽然箭头函数很适合解决this指向问题,但它也有一些局限性:
arguments对象。yield关键字(因此箭头函数不能用作生成器)。new来实例化(箭头函数没有[[Construct]]方法)。mounted)和方法中的this默认指向组件实例。setTimeout、Promise)时,需要特别注意this的指向。v-on绑定的事件处理方法,this也指向组件实例。<button @click="handleClick">Click</button> <!-- handleClick中的this指向组件 -->在Vue中,回调函数里this指向错误的根本原因是JavaScript的this绑定机制。要解决这个问题,可以使用箭头函数、提前保存this或者使用bind()方法。开发过程中,要时刻留意函数的调用方式,明确this的指向。