Photo by Vadim Bogulov on Unsplash
前端开发这么久,还是不懂
this
? 今天,彻底搞懂!
JavaScript 中的 this
是一个动态绑定的关键字,它的值由 函数调用方式 和 执行上下文 共同决定。下面我会通过分类、示例和核心规则,帮助你彻底理解 this
的各种场景。
一、核心规则:this
的绑定机制
this
的值在函数被调用时确定,而非定义时。以下是 this
的 5 种绑定规则:
规则 | 场景示例 | this 指向 |
优先级 |
---|---|---|---|
默认绑定 | 独立函数调用 | 全局对象(严格模式为 undefined ) |
最低 |
隐式绑定 | 作为对象方法调用 | 调用该方法的对象 | 中 |
显式绑定 | 使用 call /apply /bind |
手动指定的对象 | 高 |
new 绑定 |
构造函数调用 | 新创建的实例对象 | 最高 |
箭头函数 | 箭头函数 | 外层作用域的 this (词法绑定) |
不适用 |
二、普通函数中的 this
1. 默认绑定(独立调用)
javascript
function showThis() {
console.log(this);
}
showThis(); // 浏览器中输出 window(非严格模式)
// 严格模式("use strict")下输出 undefined
2. 隐式绑定(作为对象方法调用)
javascript
const obj = {
name: "Alice",
sayName() {
console.log(this.name); // this 指向 obj
},
};
obj.sayName(); // "Alice"
3. 隐式丢失问题
当方法被赋值给变量或作为回调时,this
可能丢失:
javascript
const say = obj.sayName;
say(); // 输出 undefined(this 指向全局对象)
setTimeout(obj.sayName, 100); // 输出 undefined(this 指向全局对象)
三、箭头函数中的 this
箭头函数 没有自己的 this
,它会 继承外层作用域(定义时的上下文)的 this
。
1. 基本示例
javascript
const obj = {
name: "Bob",
sayName: () => {
console.log(this.name); // this 继承外层作用域(此处为全局对象)
},
};
obj.sayName(); // 输出 undefined(浏览器中全局 name 不存在)
2. 在普通函数内部的箭头函数
javascript
function outer() {
const innerArrow = () => {
console.log(this); // 继承 outer 的 this
};
innerArrow();
}
outer.call({ name: "Alice" }); // 输出 { name: "Alice" }
outer(); // this 指向全局对象
const obj = {
name: 'will',
test: outer
}
obj.test(); // this 指向 obj
四、显式绑定:call
/apply
/bind
手动指定 this
的值:
javascript
function greet() {
console.log(`Hello, ${this.name}`);
}
const alice = { name: "Alice" };
const bob = { name: "Bob" };
// 临时绑定
greet.call(alice); // "Hello, Alice"
greet.apply(bob); // "Hello, Bob"
// 永久绑定(返回新函数)
const greetAlice = greet.bind(alice);
greetAlice(); // "Hello, Alice"
五、构造函数中的 this
通过 new
调用构造函数时,this
指向新创建的实例:
javascript
function Person(name) {
this.name = name;
}
const alice = new Person("Alice");
console.log(alice.name); // "Alice"
六、事件监听器中的 this
在 DOM 事件处理函数中,this
指向触发事件的元素:
javascript
document.querySelector("button").addEventListener("click", function() {
console.log(this); // 输出按钮元素
});
七、严格模式下的 this
严格模式("use strict"
)下,独立调用的函数 this
为 undefined
:
javascript
"use strict";
function strictThis() {
console.log(this); // undefined
}
strictThis();
八、嵌套函数中的 this
1. 普通函数嵌套
javascript
const obj = {
name: "Alice",
outer() {
function inner() {
console.log(this); // 默认绑定,指向全局对象
}
inner();
},
};
obj.outer(); // 输出 window(非严格模式)
2. 箭头函数嵌套解决 this
丢失
javascript
const obj = {
name: "Alice",
outer() {
const inner = () => {
console.log(this); // 继承 outer 的 this(指向 obj)
};
inner();
},
};
obj.outer(); // 输出 obj
九、总结:this
的决策流程图
javascript
判断函数类型 → 是否是箭头函数?
├─ 是 → 继承外层作用域的 `this`
└─ 否 → 判断调用方式:
├─ new 调用 → 指向新实例
├─ call/apply/bind → 指向指定对象
├─ 对象方法调用 → 指向该对象
└─ 独立调用 → 严格模式为 undefined,否则全局对象
十、常见误区与解决方案
-
回调函数中的
this
丢失使用箭头函数或显式绑定:
javascriptsetTimeout(() => obj.sayName(), 100); // 箭头函数继承外层 this setTimeout(obj.sayName.bind(obj), 100); // 显式绑定
-
对象方法赋值后
this
丢失使用箭头函数或在构造函数中绑定:
javascriptclass MyClass { constructor() { this.method = this.method.bind(this); } method() { /* ... */ } }
通过以上分类和示例,你应该能全面掌握 JavaScript 中 this
的行为规律。记住:this
的值由调用方式决定,箭头函数是唯一的例外(词法绑定)。