深入解析Javascript中的this指向
- 定义问题
- this的基本规则
- Vue2 中的 `this` 问题
- 问题场景:`this` 丢失
- 解决方案:保存 `this` 的引用
- 现代方法:使用箭头函数
- 为什么仍然有人定义 `self = this`?
- 总结
在 JavaScript 中,this
是一个非常重要但也容易让人困惑的概念,因为它的值是动态的,会根据使用的上下文有所不同。在 Vue2 的开发中,尤其是在函数或方法中,常常会看到有人给 this
赋值到一个变量(例如 const self = this;
或 let _this = this;
)。这是为了应对 this
的动态绑定问题。
接下来,我会详细解释 this
的工作原理以及为什么会出现这种用法。
定义问题
this
是什么?它的值是如何决定的?为什么在 Vue2 开发中会给 this
单独定义一个变量?
this的基本规则
-
全局上下文
- 在浏览器中,直接调用
this
指向全局对象window
:console.log(this); // 在全局作用域中输出 window
- 在严格模式下,
this
为undefined
:'use strict'; console.log(this); // 输出 undefined
- 在浏览器中,直接调用
-
对象方法调用
- 如果
this
在一个对象的方法中,通常指向调用这个方法的对象:const obj = {name: 'Vue',getName() {return this.name;}, }; console.log(obj.getName()); // 输出 'Vue'
- 如果
-
构造函数或类
- 在构造函数中,
this
指向新创建的实例:function Person(name) {this.name = name; } const person = new Person('Vue'); console.log(person.name); // 输出 'Vue'
- 在构造函数中,
-
箭头函数
- 箭头函数不会创建自己的
this
,它会捕获定义时所在的上下文的this
:const obj = {name: 'Vue',getName: () => {console.log(this.name); // 这里的 this 指向定义时的上下文}, }; obj.getName(); // 输出 undefined
- 箭头函数不会创建自己的
-
动态绑定
- 调用方式(
call
、apply
、bind
)会动态绑定this
:function sayHello() {console.log(this.name); } const user = { name: 'Vue' }; sayHello.call(user); // 输出 'Vue'
- 调用方式(
Vue2 中的 this
问题
在 Vue2 中,组件的实例通过 this
访问,例如:
export default {data() {return {message: 'Hello Vue!',};},methods: {showMessage() {console.log(this.message); // 正常输出 'Hello Vue!'},},
};
问题场景:this
丢失
当我们在方法中使用函数时,尤其是回调函数,this
的指向可能会丢失。例如:
-
普通函数导致的丢失
methods: {delayedMessage() {setTimeout(function () {console.log(this.message); // 这里的 this 指向了 window(或 undefined,取决于严格模式)}, 1000);}, },
-
回调函数
methods: {fetchData() {someAsyncFunction(function () {console.log(this.message); // 这里的 this 也不再指向 Vue 实例});}, },
解决方案:保存 this
的引用
为了确保回调函数中仍然可以访问 Vue 实例的上下文,我们通常会将 this
赋值给一个变量(例如 self
或 _this
):
methods: {delayedMessage() {const self = this; // 保存当前 thissetTimeout(function () {console.log(self.message); // 这里使用 self 而不是 this}, 1000);},
},
这种方式避免了 this
动态绑定问题,因为 self
是一个普通的变量,它不会因为上下文变化而改变。
现代方法:使用箭头函数
箭头函数的 this
是在定义时绑定的,它会捕获外层函数的 this
。因此我们可以直接使用箭头函数来解决:
methods: {delayedMessage() {setTimeout(() => {console.log(this.message); // 箭头函数保证了 this 指向 Vue 实例}, 1000);},
},
这是一种更优雅的解决方案,适合现代 JavaScript 开发。
为什么仍然有人定义 self = this
?
- 兼容性:箭头函数是 ES6 特性,如果需要兼容旧环境,定义
self
是更通用的解决方案。 - 老代码习惯:一些老的项目中,团队可能习惯了这种方式。
- 更明确的语义:某些场景下,使用
self
能够明确地表明它是一个保存上下文的引用。
总结
this
是动态绑定的,指向取决于调用的上下文。- 在 Vue2 中,常见的
this
丢失场景包括回调函数和普通函数。 - 解决方案:
- 使用
const self = this;
保存引用。 - 使用箭头函数(推荐)。
- 使用