JavaScript 中的 this 是一个复杂而强大的概念。本文将从原理到实践,全面解析 this 的工作机制,帮助你彻底掌握这个关键概念。
函数 foo 中的 this 判断流程
要准确判断函数中的 this 指向,我们需要按照以下流程进行分析:
graph TD
A[判断函数类型] --> B[箭头函数]
A --> C[普通函数]
A --> D[通过call、apply、bind改变this指向]
B --> E[包裹箭头函数的第一个普通函数的this]
C --> F[函数如何调用]
F --> I[除了new的方式]
F --> J[new方式]
I --> K[this为window]
I --> L[this为obj]
J --> M[this指向化在实例对象上]
D --> N[第一个参数是this]
第一步:判断函数类型
首先,我们需要判断函数是以下三种类型之一:
1. 箭头函数
- 箭头函数没有自己的 this
- this 值继承自包裹它的第一个普通函数的 this
const obj = {
foo: function() { // 普通函数
const arrow = () => {
console.log(this); // this 继承自 foo,指向 obj
};
arrow();
}
};2. 普通函数
需要继续判断函数如何调用:
// 1. 直接调用 foo()
function foo() {
console.log(this); // this 为 window
}
foo();
// 2. 作为对象方法调用 obj.foo()
const obj = {
foo: function() {
console.log(this); // this 指向 obj
}
};
obj.foo();
// 3. new 方式调用
function Foo() {
this.name = 'instance';
console.log(this); // this 指向新创建的实例对象
}
new Foo();3. 通过 call、apply、bind 改变 this 指向
- this 指向第一个参数
- 如果第一个参数为 null 或 undefined,this 指向 window
function foo() {
console.log(this);
}
const obj = { name: 'obj' };
// call/apply 方式
foo.call(obj); // this 指向 obj
foo.apply(obj); // this 指向 obj
// bind 方式
const boundFoo = foo.bind(obj);
boundFoo(); // this 指向 obj特殊情况处理
1. this 绑定丢失
const obj = {
foo: function() {
console.log(this);
}
};
// 方法赋值给变量后调用
const { foo } = obj;
foo(); // this 为 window2. 嵌套函数中的 this
const obj = {
foo: function() {
function inner() {
console.log(this); // this 为 window
}
inner();
// 使用箭头函数可以保持 this
const innerArrow = () => {
console.log(this); // this 指向 obj
};
innerArrow();
}
};最佳实践建议
-
判断函数类型
- 是否是箭头函数
- 是否是普通函数
- 是否使用 call/apply/bind
-
判断调用方式
- 直接调用 (foo())
- 对象方法调用 (obj.foo())
- new 调用
- call/apply/bind 调用
-
避免 this 绑定丢失
- 使用箭头函数
- 使用 bind 绑定
- 保存 this 引用 (const self = this)
调试技巧
function debugThis() {
console.log('当前 this 指向:', this);
console.log('调用方式:', new.target ? 'new调用' : '普通调用');
console.log('是否为严格模式:', (function() { return !this; }()));
}参考资源
作者注
本文章首次发布于 2019 年 02 月 19 日,如有更新会在文末标注。如果您发现任何错误或有任何建议,欢迎在评论区留言或通过邮件联系我。
最后更新:2024 年 12 月 28 日
本文章遵循 CC BY-NC-SA 4.0 协议