明天被同学问了一个 bug,属于平时很难觉察的方面,顺便写篇文章介绍一下。
起因
明天被同学求助,帮忙看看代码有什么问题,想要实现的性能很简略,就是一个登录窗口的弹出与敞开。但遇到了 bug,窗口无奈敞开。
代码展现如下,省略了局部内容,你能发现其中的问题吗?
<div class="top"> 点击,弹出登录框 </div>
<div class="box">
<span class="close"> 敞开 </span>
<div class="title"> 登录 </div>
</div>
var top = document.querySelector('.top')
var box = document.querySelector('.box')
var body = document.body
var close = document.querySelector('.close')
top.addEventListener('click', function () {
box.style.display = 'block'
body.style.background = '#b2b2b2'
})
close.addEventListener('click', function () {
box.style.display = 'none'
body.style.background = ' '
})
起初我看代码感觉逻辑挺正确的,看他的测试后果事件也正确绑定了
折腾了一会,直到让他把代码发给我,亲自调试,才发现其中的猫腻
打印 top 变量,指向的居然是 window???
每次点击敞开,都因为事件冒泡,又把敞开的窗口关上了
解决办法很简略,变量改个名就行了
但这种状况我也是第一次遇见,非常诡异,就钻研了其起因
起因
说到底,这是因为 var 所导致的 bug
咱们晓得,var 申明的变量都是绑定到 window 身上,咱们应用这些变量省略 window.
的局部,然而 window 身上自带了一些变量,它们是不可改写的。
而 var 申明已有的变量,也不会报错。这就导致咱们认为申明了一个变量并正确赋了值,实际上应用的却是浏览器内置的 window 属性。
而 window.top
属性,返回的是窗口层级最顶层窗口的援用,是个不可改写的属性。也就导致在之前代码中申明 top 节点绑定事件,事件理论却绑定到了 window 身上。
window 身上的属性很多,高达 200 个,其中不乏咱们平时罕用的变量名,name
length
parent
self
等。只是比拟侥幸的是,这些变量都是可写的,咱们申明它们并应用,不会引发什么谬误。
为什么又说是因为 var 导致的呢?因为如果你应用 let 定义 top 变量,会间接报错
let top = 1 // SyntaxError: Identifier 'top' has already been declared
对于那些可写的 window 属性,let 能够失常申明并赋值,不会批改 window 上的属性,应用时也是用 let 申明的变量。
解决
这种问题。不常常遇到,但真遇到了,很难排查进去。
window 属性那么多,当前还会一直新增,搞不好什么时候就遇到了。
在此提出一个解决办法:一是要回绝应用 var
只用 let
const
来申明变量,二是开启 JavaScript 文件的查看性能。
在 vscode 中,能够在 setting.json 文件中设置 "js/ts.implicitProjectConfig.checkJs": true
来启用 JavaScript 文件的语义查看。
这个语义查看性能很好用,能帮你排查 js 文件中不合标准的中央,比方参数类型,变量是否已申明等等,有助于咱们养成良好的代码习惯。
结语
如果文中有谬误或不谨严的中央,请务必给予斧正,非常感激。
如果喜爱或者有所启发,心愿能点赞关注,激励一下作者。