ES6类方法未自动绑定this:“prototype methods don't bind on extraction”含义解析
咱们先拆解这个短语:bind on extraction,直译过来是“提取时绑定”,核心要搞懂两个点——什么是「提取」,什么是「绑定」。
1. 先搞懂「提取」是啥操作
你可以把对象的方法想象成依附在对象身上的工具,「提取」就是把这个工具从对象上拆下来单独用:比如把方法赋值给一个变量、作为回调传给setTimeout、或者放到另一个对象里。举个例子:
class User { greet() { console.log(`Hi, I'm ${this.name}`); } } const alice = new User(); alice.name = 'Alice'; // 这就是「提取」操作:把alice的greet方法拿出来存到变量里 const sayHello = alice.greet;
2. 「bind on extraction」的含义
如果一个方法支持「bind on extraction」,意思就是当你把它从对象上提取出来的时候,它会自动把this固定绑定到原对象上。不管之后怎么调用这个提取出来的方法,this都不会变。
但ES6的类原型方法(就是你直接在类里写的方法)不支持这个特性——这就是那句“prototype methods don't bind on extraction”的意思。比如上面的例子,你调用sayHello()的时候:
sayHello(); // 严格模式下会报错,因为this是undefined;非严格模式下指向全局对象
这时候this已经不是原来的alice了,因为提取的时候没绑定。
3. 那直接调用obj.func()的时候算啥?
当你直接用obj.func()这种方式调用时,this确实会指向obj,但这是调用时的临时绑定,不是「提取时绑定」。这种绑定是JS的方法调用规则决定的:只要函数是作为对象的属性被调用,this就自动指向该对象。但一旦你把方法从对象上拆下来,这个绑定关系就消失了——调用时this会根据调用方式重新确定(比如全局调用就是全局对象/undefined)。
4. 为啥ES6要这么设计?
其实是为了和ES5的原型行为保持一致。ES5里的原型方法本来就不会自动绑定this,ES6类只是语法糖,延续了这个设计。而且这样更灵活:有时候你可能希望方法能被复用,绑定到其他对象上;或者把它当作普通函数来用,不想被固定的this限制。
如果确实需要「提取时绑定」的效果,你可以用类字段+箭头函数的方式:
class User { greet = () => { console.log(`Hi, I'm ${this.name}`); } } const alice = new User(); alice.name = 'Alice'; const sayHello = alice.greet; sayHello(); // 正常输出 "Hi, I'm Alice"
箭头函数的this是在定义时就绑定到实例的,相当于实现了「提取时绑定」的效果。
内容的提问来源于stack exchange,提问作者PatS

