原生和Vue中使用this的这几个坑你都知道吗? - 掘金 (juejin.cn)
在JavaScript中,this
是一个特殊的关键字,它在函数被调用时自动定义。this
的值在函数被调用时决定,取决于调用的上下文(context),它代表了函数运行时的当前对象。
让我们来看几种不同的情况下this
的指向:
全局上下文:在全局作用域中,this
指向全局对象。在浏览器环境中,全局对象是window
。
console.log(this); // window 对象
对象方法:当一个函数作为某个对象的方法被调用时,this
指向调用该方法的对象。
const obj = {
prop: 'Hello',
method: function() {
console.log(this.prop); // 输出 'Hello'
}
};
obj.method(); // 调用 obj 的 method 方法,此时 this 指向 obj
单独调用:如果函数是单独调用的(不是作为对象的方法,也不是通过new
关键字),那么this
通常指向全局对象(在浏览器中是window
)。
function testFunc() {
console.log(this); // window 对象
}
testFunc(); // 单独调用函数
构造函数:当函数通过new
关键字被调用时,它作为一个构造函数,此时this
指向新创建的对象实例。
function Person(name) {
this.name = name;
}
const john = new Person('John'); // 创建一个新的 Person 实例,this 指向 john
console.log(john.name); // 输出 'John'
事件监听器:在事件监听器内部,this
通常指向触发事件的元素。
const button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log(this); // 指向 button 元素
});
箭头函数:箭头函数不绑定自己的this
,它继承自包围它的函数或全局作用域的this
。
function OuterFunction() {
this.value = 'outside';
const innerFunc = () => {
console.log(this.value); // 输出 'outside',而不是 'inside'
};
this.innerFunc = innerFunc;
}
const outer = new OuterFunction();
outer.innerFunc(); // 调用箭头函数,this 继承自 OuterFunction 的上下文
this
当你在 Vue 实例的方法中使用 this
时,它指向的是该 Vue 实例。这允许你访问 Vue 实例的 data
、methods
、computed
等属性。
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
showMessage: function() {
console.log(this.message); // 这里的 this 指向 Vue 实例
}
},
created: function() {
this.showMessage(); // 调用实例方法
}
});
this
在 Vue 组件中,this
同样指向组件实例。你可以在组件的 methods
、computed
、watch
、mounted
等选项中使用 this
。
Vue.component('my-component', {
data: function() {
return {
localMessage: 'Hello from component!'
};
},
methods: {
showLocalMessage: function() {
console.log(this.localMessage); // 这里的 this 指向组件实例
}
},
mounted: function() {
this.showLocalMessage(); // 调用组件方法
}
});
this
在 Vue 中使用箭头函数时,this
的行为会有所不同。箭头函数不会创建它自己的 this
上下文,因此 this
在箭头函数中指向的是定义时所在的上下文。如果你在 Vue 的方法中使用了箭头函数,那么 this
将不会指向 Vue 实例,而是指向定义该箭头函数时的上下文。
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
showMessage: () => {
console.log(this.message); // 这里的 this 不指向 Vue 实例,而是指向定义时的上下文,可能会导致错误
}
},
created: function() {
this.showMessage(); // 调用实例方法
}
});
在上面的例子中,showMessage
方法是一个箭头函数,因此 this
在 showMessage
中不会指向 Vue 实例。这通常不是 Vue 中推荐的做法,因为它可能导致混淆和难以调试的错误。
在 Vue 实例的方法中定义一个普通函数时,这个函数的
this
上下文确实会被绑定到 Vue 实例上。这是因为 Vue 在创建实例时会自动绑定方法中的this
。所以,在 Vue 的方法中使用普通函数时,this
会指向 Vue 实例,而不是全局对象(在浏览器中是window
)。new Vue({ el: '#app', data: function() { return { message: 'Hello Vue!' }; }, methods: { showMessage: function() { console.log(this.message); // 这里的 this 指向 Vue 实例 } }, created: function() { setTimeout(this.showMessage, 1000); // 这里的 this 仍然指向 Vue 实例 } });
在这个例子中,即使
showMessage
方法是作为setTimeout
的回调函数传递的,this
仍然指向 Vue 实例,因为 Vue 在创建实例时已经确保了方法的this
上下文。然而,如果您在 Vue 实例的方法之外定义了一个函数,并且这个函数被用作回调函数或其他情况,那么您需要确保
this
的正确上下文。在这种情况下,您可以使用箭头函数来捕获 Vue 实例的this
上下文,因为箭头函数不会创建自己的this
上下文。例如:
new Vue({ el: '#app', data: function() { return { message: 'Hello Vue!' }; }, methods: { startTimer: function() { let vm = this; // 保存 Vue 实例的引用 setInterval(() => { // 使用箭头函数 console.log(vm.message); // 通过保存的引用来访问 message }, 1000); } }, created: function() { this.startTimer(); } });
在这个例子中,我们使用了一个箭头函数作为
setInterval
的回调函数。由于箭头函数不绑定自己的this
,它会继承包围它的函数的this
上下文,即 Vue 实例。因此,我们不需要在startTimer
方法中创建一个额外的变量来保存this
的引用,可以直接通过this.message
来访问数据属性。总结来说,在 Vue 实例的方法中直接使用普通函数时,
this
会正确指向 Vue 实例。但是,当您需要将函数作为回调函数或其他情况使用时,可能需要使用箭头函数来确保this
的正确上下文。