<script type="text/javascript">
for (var i = 0; i < 3; i++) {
function onclick(e) {
document.write(222)
}
}
</script>
如上代码,会被加上点击事件,莫名奇妙
而且将onclick
不放在for
循环里时,并没有这个现象
<script type="text/javascript">
for (var i = 0; i < 3; i++) {
function onclick(e) {
document.write(222)
}
}
</script>
如上代码,会被加上点击事件,莫名奇妙
而且将onclick
不放在for
循环里时,并没有这个现象
这个应该跟浏览器解析块级函数声明有关。理论上来说函数不应在块级作用域中声明
https://developer.mozilla.org...
从ECMAScript 6开始,在严格模式下,块里的函数作用域为这个块。ECMAScript 6之前不建议块级函数在严格模式下使用。
你现在就是在for语句中声明了函数,在chrome、firefox中应该是等效为window.onclick = ....
如果你在IE中查看就不会有这样的效果。
chrome控制台提供了一个API来查看事件绑定。看下图:
当onclick在全局中声明时,就是一个正常的全局函数,并不会绑定window.onclick
而如果是在for语句中声明则会绑定事件:
所以,千万不要在块级语句中声明函数,这个行为很奇怪
window.onclick
就是相当于注册点击事件
然后看下这个例子:
window.abc = null
function abc() {
console.log(1)
}
console.log(window.abc) // null
再看下这个例子,括号里是不是就是你发的代码:
window.abc = null
{
function abc() {
console.log(1)
}
}
console.log(window.abc) // abc
你可以理解 浏览器在最开始把window.onckick
赋值为null
,如果在声明函数的时候不是在大括号内,函数就会声明提示导致声明在window.onclick = null
前面就无法重新赋值
感觉是 chrome 的 bug。
我们来做一个实验。(以下结果来自 Chrome/83.0.4103.61)
var _a = null;
Object.defineProperty(window, 'a', {
configurable: true,
enumerable: false,
get () {return _a;},
set (v) {_a=v;console.log('set a to', v)}
});
window.a = 1; // set a to 1
window.a // 1
var a = 2 // set a to 2
window.a // 2
{ var a = 3; } // set a to 3
window.a // 3
{ function a(){} } // set a to f a(){}
window.a // f a(){}
window.a === window._a // true
function a(){} // nothing
window.a // f a(){}
window.a === window._a // false
Object.getOwnPropertyDescriptor(window, 'a') // 已经不是我们第一步 define 的 内容了
由此可见,顶层代码块中的 var / function delcaration 会触发 window 上对应 property 的 setter,如果没有则 define 一个,而直接在顶层的 var / function declaration 则会直接触发 window 对象上的 defineProperty,如果已经存在且 configurable 为 true 则覆盖,为 false 则报错。
我们看看 window.onclick 是什么,
Object.getOwnPropertyDescriptor(window, 'onclick')
// {
// configurable: true
// enumerable: true
// get: ƒ onclick()
// set: ƒ onclick()
// }
chrome 中 onclick 是通过 setter 来完成事件注册的, 猜测 setter 内部调用了 addEventListener。 顶层的 function onclick(){}
会调用 define property, 而顶层代码块中的 function onclick(){}
则会调用 set property,本质和 window.onclick = ...
是一回事。 个人觉得顶层代码块中的 var / function 既然也会提升,那也应该使用 define 语义。
这玩意儿真是 JS 的糟粕。 两个糟粕碰一起就更加莫名其妙了。
13 回答12.9k 阅读
8 回答2.6k 阅读
2 回答5.1k 阅读✓ 已解决
7 回答2.1k 阅读
3 回答2.2k 阅读✓ 已解决
5 回答1.3k 阅读
3 回答1.3k 阅读✓ 已解决
这似乎是2个问题:
step1. 块级作用域内定义函数,相当于使用
var
定义一个函数阮一峰 es6 中有提及

那么代码可以看成
step2.
var
定义变量相当于在添加全局属性(window.x
)那么,就得到如下代码
显而易见,这个就是给window绑定事件了
应该就是这2个原因了
ps: 我查了下
window.x
与var x
的区别@scort 提及,唯一的确保在于

configurable
属性,这就是为什么var
定义的变量使用delete window.x
删除MDN对

configurable
的描述