一,为什么需要块级作用域
ES5只有全局作用域和函数作用域,比如我们常常碰到的用来计数的循环变量泄露为全局变量。
例如:用 js 连续创建 10 个 a 标签,点击的时候弹出来对应的序号。
1,错误做法
<script>
for(var i = 0; i < 10; i++){
var a = document.createElement('a');
a.innerHTML=i + '<br>';
document.body.appendChild(a);
a.addEventListener('click',function () {
alert(i);
});
}
</script>
//点击哪个序号的链接弹出的都是10
上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,点击链接时触发绑定的click方法里面的i也是同一个i,所以弹出的值是10。
2,正确做法一:利用闭包,把i作为函数参数值传递给内部函数。
//第一种写法
<script type="text/javascript">
for(var i = 0;i<10;i++){
var a = document.createElement('a');
a.innerHTML=i+'<br>';
document.body.appendChild(a);
a.addEventListener('click',(function (i) {
return function () {
alert(i);
}
})(i))
}
</script>
//第二种写法
for(var i=0;i<10;i++)
{
(function (i) {
var a = document.createElement('a');
a.innerHTML=i+'<br>';
document.body.appendChild(a);
a.addEventListener('click',function () {
alert(i);
});
})(i);
}
3,正确做法二:利用let的块级作用域
<script>
for(let = 0; i < 10; i++){
var a = document.createElement('a');
a.innerHTML=i + '<br>';
document.body.appendChild(a);
a.addEventListener('click',function () {
alert(i);
});
}
</script>
4,没有块级作用域造成的不合理还有:内存变量可能覆盖外层变量。
<script>
var a = 10;
function test() {
console.log(a); //undefined
var a = 'hello';
}
test();
</script>
因为在test函数的声明了a变量,变量提升了,覆盖了函数外部的变量a。
二,ES6的块级作用域
块级作用域通常放在大括号里面,没有返回值。
ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
1、允许块级作用域任意嵌套,外层作用域无法读取内层作用域的变量
{{{{
{let i = 6;}
console.log(i); // 报错
}}}}
2,内层作用域可以定义外层作用域的同名变量。
{{{{
let i = 5;
{let i = 6;}
}}}}
3,块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。
// IIFE 写法
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}