JavaScript对象方法作为事件回调时this返回undefined的问题咨询
你遇到的这个问题是JavaScript中this绑定规则的经典场景,我来帮你理清楚原因和解决办法:
为什么会输出undefined?
当你把this.getFoo作为回调函数传给window.addEventListener时,本质上是把getFoo函数的引用单独传递给了事件监听机制。当scroll事件触发时,浏览器会在window的上下文环境中调用这个函数,此时this就指向了window对象。而window上并没有foo属性,所以console.log(this.foo)自然输出undefined。
简单来说:普通函数的this指向是由调用它的方式决定的,而不是定义它的位置。
几种可行的解决方案
方案1:用箭头函数包裹回调(最简洁)
箭头函数的this是继承自它定义时的外层作用域,不会被调用方式改变。在你的method里,外层作用域的this指向myObj,所以用箭头函数包裹getFoo调用就能保证this正确:
let myObj = { foo: "bar", getFoo: function() { console.log(this.foo); }, method: function() { if (true) { // 箭头函数继承method里的this(即myObj) window.addEventListener('scroll', () => this.getFoo()); } else { window.removeEventListener('scroll', () => this.getFoo()); } } } window.addEventListener('click', () => { myObj.method(); });
⚠️ 注意:如果需要移除事件监听,这种方式每次都会生成新的箭头函数,所以remove的时候无法匹配到之前添加的回调。如果你的代码需要支持移除事件,建议用下面的方案2。
方案2:用bind绑定this(适合需要移除事件的场景)
bind方法会返回一个新函数,这个函数的this会被永久绑定到你指定的对象上。为了保证添加和移除的是同一个函数,最好把绑定后的函数存到对象的属性里:
let myObj = { foo: "bar", getFoo: function() { console.log(this.foo); }, // 存储绑定后的函数,避免每次bind生成新函数 boundGetFoo: null, method: function() { // 首次调用时绑定this if (!this.boundGetFoo) { this.boundGetFoo = this.getFoo.bind(this); } if (true) { window.addEventListener('scroll', this.boundGetFoo); } else { window.removeEventListener('scroll', this.boundGetFoo); } } } window.addEventListener('click', () => { myObj.method(); });
这样添加和移除的是同一个函数引用,就能正确移除事件监听了。
方案3:把getFoo改成箭头函数(需谨慎使用)
如果把getFoo定义成箭头函数,它的this会继承自定义时的外层作用域(这里是全局作用域,即window),所以这种方式不能直接用在对象字面量里——因为对象字面量不会形成新的作用域,箭头函数的this还是指向window,依然拿不到myObj.foo。除非你是在类或者闭包中定义对象,外层作用域的this指向对象本身,否则不推荐这种方式。
内容的提问来源于stack exchange,提问作者galingong

