事实上,var的设计可以看做是JavaScript语言设计上的错误,ES6之后改用let,可以将let看成更完美的var
ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们都必须借助于function的作用域来解决应用外面变量的问题
1.变量作用域
变量作用域:变量在什么范围内是可用的
{
var name = 'why'; //代码块中定义的变量
console.log(name);
}
console.log(name);//也能访问name
2.没有块级作用域引起的问题:if的块级
var fun;
if(true){
var name = 'why';
fun = function(){
console.log(name);
}
}
name = 'how';
fun();//此时打印的是how
由于if没有块级作用域,在if中的name不是局部变量,所以在外面更改name的值时,也会随之改变
3.没有块级作用域引起的问题:for的块级
五个按钮,分别点击,控制台分别打印这五个按钮
情况一:ES5中没有使用闭包(错误的方式)
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
}
</script>
</body>
结果:点击任何按钮 i 都是 5
函数里的 i 是引用for里的 i ,本来希望 i 第一次传进来是0,第二次是1…但是for循环遍历完之后 i 变为了5,而点击任何按钮时,此时的 i 已经为5了。
4.if和for都没有块级作用域,而函数有
情况二:ES5中使用闭包
以前为了解决这个问题,利用闭包
为什么闭包能解决问题? 因为函数是一个作用域
<script>
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
(function (i) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
})(i)
}
</script>
结果:正确显示
由于函数中的 i 和外面的 i 不同,函数有自己的作用域,当改变外面的i时里面的i不受影响,将函数里的i换成num更好理解,详细过程如下:
以前一直理解为立即调用,当i传进去时立即就调用了。实际是函数有一个作用域,不会根据外面的变量值的改变而改变
使用ES6中的let,就没有上述问题
情况三:ES6中的let
ES6中,加入了let,let它是有if和for的块级作用域的
<script>
const btns = document.getElementsByTagName('button');
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '个按钮被点击');
})
}
</script>
let与var的区别
1.定义变量的作用范围
var 声明的变量 没有局部作用域
let 声明的变量 有局部作用域
{
var a = 10;
let b = 20;
}
console.log(a);
console.log(b);//报错10 Uncaught ReferenceError: b is not defined
2.定义变量特点
var 可以定义多次
let 只能定义一次
var a = 1;
var a = 2;
let b = 20;
let b = 30;
console.log(a);
console.log(b);//报错Uncaught SyntaxError: Identifier 'b' has already been declared