Appearance
JavaScript 的 this 机制深度解析
全局环境中的 this
- 在浏览器全局环境下,
this
始终指向window
对象(等同于self
) var
声明的全局变量会挂载到window
属性上let
和const
声明的变量不会挂载到window
javascript
var a = 10;
let b = 20;
console.log(this === window); // true
console.log(window === self); // true
console.log(window.a); // 10
console.log(window.b); // undefined
函数调用中的 this
严格模式 vs 非严格模式
模式 | this 指向 | 示例 |
---|---|---|
严格模式 | undefined | function f() { "use strict"; console.log(this) } → undefined |
非严格模式 | window 对象 | function f() { console.log(this) } → window |
对象方法中的 this
- 对象方法中的
this
(除箭头函数外)指向调用该方法的对象 - 当方法被提取为独立函数调用时,
this
可能丢失
javascript
const obj = {
name: "hulei",
getName() {
return this.name;
},
};
console.log(obj.getName()); // "hulei" (this指向obj)
const getNameFunc = obj.getName;
console.log(getNameFunc()); // undefined (this指向window)
构造函数中的 this
- 构造函数中的
this
默认指向新创建的实例对象 - 如果构造函数返回对象,则
this
指向该返回对象 - 如果返回非对象值,则
this
仍指向实例对象
javascript
function User(name) {
this.name = name;
}
const user1 = new User("Alice");
console.log(user1.name); // "Alice" (this指向实例)
function Admin(name) {
this.name = name;
return { name: "Admin User" }; // 返回对象
}
const admin = new Admin("Bob");
console.log(admin.name); // "Admin User" (this指向返回对象)
call & apply 改变 this 指向
- 使用
call
或apply
可以显式改变函数的this
指向 - 箭头函数的
this
无法通过call
或apply
改变
javascript
function greet() {
console.log(`Hello, ${this.name}`);
}
const person = { name: "John" };
greet.call(person); // "Hello, John"
箭头函数的 this
核心特性
- 箭头函数的
this
在定义时确定,而非调用时 - 指向定义时上层作用域的
this
- 无法通过
call
、apply
或bind
改变this
指向
不同场景表现
场景 | this 指向 | 原因说明 |
---|---|---|
对象方法 | 外层作用域的 this | 通常是 window |
普通函数内部 | 外层函数的 this | 取决于外层函数调用方式 |
构造函数内部 | 新创建的实例对象 | 箭头函数定义在构造函数作用域内 |
全局作用域 | window 对象 | 最外层作用域 |
javascript
const obj = {
value: "object value",
regularMethod: function () {
console.log("Regular method:", this.value);
},
arrowMethod: () => {
console.log("Arrow method:", this.value);
},
nested: function () {
const innerArrow = () => {
console.log("Nested arrow:", this.value);
};
innerArrow();
},
};
obj.regularMethod(); // "Regular method: object value"
obj.arrowMethod(); // "Arrow method: undefined" (指向window)
obj.nested(); // "Nested arrow: object value" (指向obj)
this 绑定规则总结
规则类型 | this 指向 | 优先级 | 是否可改变 |
---|---|---|---|
new 绑定 | 新创建的实例对象 | 最高 | ❌ |
显式绑定 | call/apply/bind 指定 | 高 | ✅ |
隐式绑定 | 调用上下文对象 | 中 | ✅ |
默认绑定 | 全局对象或 undefined | 最低 | ✅ |
箭头函数 | 定义时的外层 this | 固定 | ❌ |
经典案例分析
案例 1:对象方法与嵌套函数
javascript
const point = {
x: 20,
moveTo: function(x) {
// 普通函数,this 取决于调用方式
const moveX = function(x) {
this.x = x; // this 指向 window
};
moveX(x);
},
getX: function() {
return this.x; // this 指向调用对象
}
};
point.moveTo(1);
console.log(point.getX()); // 20 (未改变)
// 解决方案:使用箭头函数或绑定 this
moveTo: function(x) {
const moveX = (x) => {
this.x = x; // this 指向 point
};
moveX(x);
}
案例 2:箭头函数与对象方法
javascript
const obj = {
value: 42,
getValue: function () {
// 箭头函数捕获外层 this
const arrowFn = () => {
console.log(this.value); // 42 (指向 obj)
};
arrowFn();
// 尝试改变 this 指向失败
arrowFn.call({ value: 100 }); // 仍输出 42
},
getValueArrow: () => {
// 箭头函数直接定义在对象中
console.log(this.value); // undefined (指向 window)
},
};
obj.getValue(); // 42
obj.getValueArrow(); // undefined
案例 3:类与箭头函数
javascript
class Counter {
count = 0;
// 原型方法:this 动态绑定
increment() {
this.count++;
console.log(this.count);
}
// 实例方法(箭头函数):this 静态绑定
decrement = () => {
this.count--;
console.log(this.count);
};
}
const counter = new Counter();
const increment = counter.increment;
const decrement = counter.decrement;
increment(); // TypeError: Cannot read property 'count' of undefined
decrement(); // -1 (箭头函数绑定实例)
箭头函数特殊性质
- 没有自己的
this
:继承自定义时的外层作用域 - 没有
prototype
属性:不能作为构造函数使用 - 没有
arguments
对象:需使用剩余参数(...args)
替代 - 不能使用
new
调用:没有构造能力
javascript
const arrow = () => {};
console.log(arrow.prototype); // undefined
try {
new arrow(); // TypeError: arrow is not a constructor
} catch (e) {
console.error(e.message);
}
最佳实践建议
- 对象方法:使用普通函数确保
this
正确指向调用对象 - 回调函数:使用箭头函数避免
this
丢失问题 - 类组件:使用箭头函数绑定实例方法
- 工具函数:优先使用箭头函数避免意外的
this
绑定 - 构造函数:避免使用箭头函数定义方法