JavaScript中this指向函数调用时的上下文而非定义时;普通调用下非严格模式为全局对象、严格模式为undefined;对象方法赋值或解构后单独调用会丢失this;点号左侧决定this指向;嵌套函数不继承外层this;构造函数中this指向新实例;箭头函数无独立this,由外层作用域决定;call/apply/bind可显式绑定this但对箭头函数无效。

JavaScript 中的 this 不是指向函数定义时的上下文,而是由函数「怎么被调用」决定的——这点最容易误判,也是绝大多数 this 相关 bug 的根源。
普通函数调用时,this 指向全局对象或 undefined
在非严格模式下,直接调用 foo(),this 指向 window(浏览器)或 global(Node.js);严格模式下是 undefined。
常见错误现象:对象方法赋值给变量后单独调用,this 丢失:
const obj = {
name: 'Alice',
say() { console.log(this.name); }
};
const fn = obj.say;
fn(); // undefined(严格模式)或报错(因为 this 没有 name 属性)
- 这不是“箭头函数没用好”,而是普通函数调用规则本身如此
- 解决方式不是改用箭头函数(箭头函数不能作为方法被正常调用),而是用
.bind(obj)、obj.say.bind(obj),或调用时用obj.say()保持上下文 - ES6 解构时也容易触发此问题:
const { say } = obj; say();同样丢失this
对象方法中,this 指向调用该方法的对象
关键看「点号左边是谁」: obj.method() → this 是 obj;obj.nested.method() → this 是 obj.nested。
立即学习“Java免费学习笔记(深入)”;
但要注意嵌套函数不会继承外层 this:
const obj = {
name: 'Bob',
run() {
console.log(this.name); // 'Bob'
setTimeout(function() {
console.log(this.name); // undefined —— 这是独立函数调用
}, 100);
}
};
-
回调函数中的
this和外层无关,除非显式绑定(.bind(this))、用箭头函数(它不绑定this,而是沿作用域链向上找)、或传入thisArg(如setTimeout(() => ..., 100)) - 类方法中同理:
class C { m() { setTimeout(() => this.x) } }可行,但setTimeout(function() { this.x })不行
构造函数和 class 中,this 指向新创建的实例
用 new Foo() 调用函数时,this 是新分配的空对象,并最终被返回;class 构造器同理。
-
this在构造函数里可自由添加属性:this.id = Date.now(); - 如果忘记写
new,函数会以普通方式执行,this指向全局或undefined,极易引发意外污染或报错 - 箭头函数不能用作构造函数,调用会直接抛出
TypeError: xxx is not a constructor
call / apply / bind 显式控制 this 指向
这三个方法允许你强行指定函数运行时的 this 值,优先级高于其他所有绑定规则。
-
fn.call(obj, a, b)立即执行,this为obj -
fn.apply(obj, [a, b])同上,只是参数传数组 -
fn.bind(obj)返回一个新函数,后续调用时this固定为obj,即使再用call也无法覆盖(bind之后的bind或call无效) - 注意:箭头函数无视
call/apply/bind,它的this完全由定义时外层作用域决定,不可更改
真正难的不是记住规则,而是识别调用形式——尤其是事件回调、定时器、Promise 回调、解构赋值、高阶函数传参这些场景下,this 很可能已经脱离了直觉。每次不确定时,加一行 console.log(this) 是最稳妥的验证方式。











