this 指向的四种绑定规则与箭头函数例外
this 的取值不取决于函数在哪里定义,而取决于函数在哪里被调用。这条规则能解释绝大多数困惑。
四种绑定,优先级从低到高
1. 默认绑定:独立调用时,非严格模式指向 window,严格模式是 undefined。
function f() { console.log(this); }
f(); // window(严格模式下 undefined)
2. 隐式绑定:作为对象方法调用,this 指向调用它的对象。
const obj = { name: 'a', hi() { return this.name; } };
obj.hi(); // 'a'
const fn = obj.hi;
fn(); // undefined —— 赋值后变成了独立调用
3. 显式绑定:call / apply / bind 强制指定。
fn.call({ name: 'b' }); // 'b'
const bound = obj.hi.bind(obj);
4. new 绑定:构造函数调用时,this 指向新创建的对象。优先级最高。
箭头函数没有自己的 this
箭头函数在定义时捕获外层 this,之后无法被 call、bind 改变。这让它在回调里特别好用:
const timer = {
seconds: 0,
start() {
setInterval(() => { this.seconds++; }, 1000); // this 是 timer
}
};
如果写成 function () {},this 会指向全局对象,seconds 就加到了错误的地方。
但箭头函数不能用作构造函数,也没有 arguments。需要动态 this 的场景必须用普通函数。
常见踩坑
- 回调丢失上下文:把方法作为参数传递时,先
bind或改用箭头函数; - 事件处理器:
addEventListener里的this是绑定元素,但箭头函数会捕获外层; - 对象字面量里的方法简写:
{ hi() {} }是普通函数,不是箭头函数; - 类方法解构:
const { hi } = obj; hi()同样丢失this。
一个判断口诀
看调用表达式左边的点:有点,点前面是谁就指向谁(除非被 bind 固定);没有点,看是否用 new,都没有就是默认绑定;箭头函数直接跳过以上全部,找定义位置的 this。
实际写业务代码时,尽量少依赖 this——把需要的状态作为参数传入,或者用闭包保存。可读性通常更好。