为何document.body事件处理函数中的this指向全局window对象?
先贴下你提供的代码方便大家对照:
<!DOCTYPE html> <html> <head> <style type="text/css"> body { height: 1000px; } </style> <title>Scroll</title> </head> <body> <button id="btn">click</button> <script type="text/javascript"> document.body.onscroll = function() { alert(this);// displays [object Window], instead of [object HTMLBodyElement] }; document.getElementById('btn').onclick = function() { alert(this);// displays [object HTMLButtonElement] } </script> </body> </html>
这事儿本质是浏览器对body元素scroll事件的特殊处理逻辑,跟普通元素的事件绑定规则不一样:
像
button这种普通元素,当你直接给onclick赋值函数时,这个函数是由触发事件的元素本身调用的,所以this自然指向这个button——这是DOM事件处理的常规表现,完全符合预期。但
body的scroll事件是个例外:浏览器里真正负责处理页面整体滚动的是window对象,body本身并不会触发scroll事件。当你给document.body.onscroll赋值时,浏览器会偷偷把这个函数代理绑定到window.onscroll上。等页面滚动时,是window在调用这个函数,那this肯定就指向window了。
如果想要让body的滚动事件处理里this指向body元素,有两个简单的解决办法:
- 用
addEventListener绑定事件,它能正确保留元素的上下文:
document.body.addEventListener('scroll', function() { alert(this); // 这会儿就会显示[object HTMLBodyElement]了 });
不过要注意:这种方式只有当body自己有独立滚动条(比如设置了overflow: scroll且内容超出容器)时才会触发。如果是整个页面的滚动,还是得监听window的scroll事件。
- 直接在函数里用
document.body代替this:
document.body.onscroll = function() { alert(document.body); // 直接指定指向body,简单省心 };
总结一下:普通元素的on[event]绑定遵循常规逻辑,但body的onscroll因为浏览器的代理机制,实际是window在触发事件,所以this就跑偏到window了。
内容的提问来源于stack exchange,提问作者marcel
相关产品推荐
相关产品推荐

