目录
1. let,const 和 var 有块级作用域的区别,但块级作用域是什么呢?
var, let和const的区别
var(es5-用于声明变量)
-
变量可以重复声明,打印出的是最后一次声明内容;let,const不能重复声明
-
变量声明会被提升;(函数的声明也会被提升)let,const不会提升
-
var声明的变量没有局部作用域;let,const有块级作用域
let(es6-用来取代var)
-
不能重复声明;不会提升;有块级作用域
-
不影响作用域链
const(es6-用来声明常量)
-
不能重复声明;不会提升;有块级作用域
-
不能修改(对于数组和对象元素/属性的修改不算作常量修改。原因:该常量所指向的地址没有改变)
-
const 使用场景:声明的匿名函数,箭头函数
1. let,const 和 var 有块级作用域的区别,但块级作用域是什么呢?
首先我们知道作用域分为:全局作用域,函数作用域,块级作用域。
块级作用域主要指:
if
/for
ES5中的var是没有块级作用域的(if / for)
ES6中的let是有块级作用域的(if / for)
举个例子来解释吧🌰
//var定义变量
for(var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
//结果:3,3,3
//let定义变量
for(let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
//结果:0,1,2
语法解释:
1. JS中的for循环体比较特殊,每次执行都有一个全新的独立的块作用域
2. var不支持块级作用域(var只有函数作用域和全局作用域),let支持块级作用域,所以let声明的变量只在它所在的代码块内有效。
执行过程:
定时器为异步执行,每次 for循环都将异步任务放入对应的管理模块,所以当满足条件将异步任务放入回调队列(callback queue)。for循环的执行速度很快,当 for循环执行完成之后 i=3,此时主线程任务执行完将回调钩回到主线程。
1. 对于var,不支持块级作用域,当将回调任务钩回主线程时,此时i=3,所以结果是3,3,3
2. 对于let,支持块级作用域,每个块内都有一个独立的i,当将回调任务钩回主线程时,每个任务输出对应块级作用域的i,结果是0,1,2
实际应用:循环遍历监听
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
</body>
<script type="text/javascript">
var btns = document.getElementsByTagName('button');
for (let i = 0; i<btns.length; i++){
//for (var i = 0; i<btns.length; i++){
let btn = btns[i]; //结果:依次0,1,2,3,4
//var btn = btns[i]; //结果:依次5,5,5,5,5
btn.onclick = function(){
alert(i);
}
}
</script>
🪐 ps:ES6之前因为 if 和 for 都没有块级作用域的概念,所以很多的时候,我们必须借助函数作用域(即使用闭包)来解决应用外面的变量问题。
使用立即执行函数和闭包解决问题 👆
for(var i = 0; i < 3; i++) {
(function(i){
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
<!--块级作用域应用:循环遍历加监听-->
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
</body>
<script type="text/javascript">
var btns = document.getElementsByTagName('button');
for(var i = 0; i<btns.length; i++){ //for (var i = 0; i<btns.length; i++)
(function(i){
var btn = btns[i];
btn.onclick = function(){
alert(i); //∵使用了闭包∴拿到的i不是最后的3
}
})(i)
}
</script>
2. let暂时性死区
官方解释:在这运行流程进入作用域创建变量,到变量可以被访问之间的这段时间,称为暂时死区。
通俗理解:在let/const声明之前使用会报错,在let命令声明某变量之前,都属于该变量的死区范围。
let a;
console.log(a); //Undefined
console.log(b); //报错
let b;