0%

let块级作用域及多个按钮的点击事件

学习JavaScript有一个很经典的问题:多个按钮的点击事件(循环作用域),在let关键字及块级作用域出现以前,解决这个问题可以说略显麻烦,代码也不简单明了,但是let的出现,让这个问题有了更简便的解决方式。

块级作用域

变量作用域可以简单地理解为变量的可用范围。

而以var关键字声明的变量是没有块级作用域的,这就会导致一个问题:如果想要一个变量只在一个代码块内有效,而不允许在外部访问或改变变量值,就只能通过一些方法。所以为了解决var的局限性,在ES6中,新增了let关键字,let声明的变量带来了块级作用域。

(代码块:简单的来说就是包含在一对大括号之间的代码)

1
2
3
4
5
6
{
var str = 'hello world';
console.log(str);
}
console.log(str);
//以var声明相当于全局变量,大括号外部也可以访问
1
2
3
4
5
6
{
let str = 'hello world';
console.log(str);
}
console.log(str); //str is not defined
//以let声明只在大括号内有效

多个按钮的点击事件

从ES5到ES6,多个按钮的点击事件有以下问题及解决方式。

如果使用var声明,说明 i 此时为一个全局变量,此时循环全局变量相当于一直在重复声明,重复声明导致 i 值不断被覆盖,所以在进入代码块时,它已经达成条件( i =btns.length ),然后完成点击事件。

1
2
3
4
5
6
var btns = document.getElementsByTagName('button');
for(var i=0;i<btns.length;i++){
btns[i].addEventListener('click',function(){
console.log('第'+i+"个按钮被点击");
})
}

闭包(借助于函数)解决:函数是一个作用域,传入的 i 不会被改变,分别属于每一个函数作用域。

1
2
3
4
5
6
7
8
var btns = document.getElementsByTagName('button');
for(var i=0;i<btns.length;i++){
(function(i){
btns[i].addEventListener('click',function(){
console.log('第'+i+"个按钮被点击");
})
})(i)
}

使用let声明,意味着每一个代码块都有一个作用于自己范围内的一个 i 值。

1
2
3
4
5
6
var btns = document.getElementsByTagName('button');
for(let i=0;i<btns.length;i++){
btns[i].addEventListener('click',function(){
console.log('第'+i+"个按钮被点击");
})
}

可以看到,ES6的let在一定程度上替代了闭包。