作用域
一个思考题
- 点击生成的标签a的时候提示的是什么?
let i, a
for (i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br/>'
a.addEventListener('click', function (e) {
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
带着这个问题我们来看一下作用域和自由变量。
作用域
一张图带你认知作用域。
- a 可以在红色框任意地方使用,a1可以在蓝框任意地方使用,a2可以再黄框任意地方使用,a3可以再黑框任意地方使用。
- 如果翻过来,在红框内,黑框外使用a3就会报错。
所以就会得到变量对应的使用范围,这个范围就叫做作用域。
作用域有哪些?
- 全局作用域
上述例子中 变量a
就是全局作用域,在任意地方都可以使用。 - 函数作用域
函数作用就是只能在当前函数中使用,例如a1只能在fn1中使用,超出就不能使用。 - 块级作用域
块级作用域只能在当前的块中使用,超出当前块就会报错,例如以下例子。
if (true) {
let x = 100
}
console.log(x) // x is not defined
使用var声明遍历会造成变量提升,所以建议在写代码时尽量使用let,const
关于var的变量提升,如果刚才块级作用域简单修改一下,打印的值就不一样,原因就是因为把声明a提升到了最顶部,之后赋值。
if (true) {
var x = 100
}
console.log(x) // 100
变量提升后,这样看的话就会一目了然。
var a
if (true) {
x = 100
}
console.log(x) // 100
自由变量
- 一个变量在当前作用域没有定义,但是他被使用了 。
- 他会向上级作用域进行寻找,一层一层逐渐往上,直到找到为止。
-
如果全局作用域都没有找到,就会提示XX is not defined。
还是这个图,使用a2是就向上层找,找到了a2,a1在上上层找到了,a在全局作用域找到。那么这些变量就叫做自由变量。
回到刚开始的问题,实践的答案就是每次点击都是10,那么如何解决这个问题,只需要把变量i的定义改变为块级作用域就可以解决。
let a
for (let i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br/>'
a.addEventListener('click', function (e) {
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}