块级作用域

1.块级作用域

块级作用域
在ECMAScript6(以下简称ES6)之前,ECMAScript的作用域只有两种:全局作用域;和函数作用域。
但ES6的到来,为我们提供了‘块级作用域’。凡是带{}都是块级作用域,if(){} for(){} 对象{} 。注意function后是函数作用域。
块级作用域并不影响var声明的变量。var声明的变量的性质和原来一样,还是具有‘变量提升’的特性。
而块级作用域通过新增命令let和const来体现。在块级作用域下,var 和function跟在window下一样。如果没有出现let或者const就不用考虑块级作用域了。
即:
var定义的变量,没有块作用域的概念,可以跨块访问。
let定义的变量, 有块作用域的概念,不能跨块访问。
const用来定义常量,有块作用域的概念,不能跨块访问。
他们三个都有函数作用域的概念。都是用来定义变量的。

 <script> 
      //在块级作用域下,var 和function跟在window下一样 
        {
            console.log(sing)
            sing();
            function sing(){
                console.log('aaa');
            }
        }
        window.sing();
        </script>

在这里插入图片描述

这里是引用

在这里插入图片描述

 2.let关键字

在ES6之前,我们一般都用var来定义变量
使用 let 声明的变量与 var 声明的变量有许多的不同,比如:

没有变量提升
暂时性死区
禁止重复声明
块级作用域
脱离全局作用域
等等….
(1)禁止重复声明

let不允许在相同作用域内,重复声明同一个变量。

在这里插入图片描述

在这里插入图片描述

<script> 
     console.log(a); //不会执行
     var a;
     let a; //报错Uncaught SyntaxError: Identifier 'a' has already been declared
</script>

在这里插入图片描述


(2)暂时性死区/临时性死区(Temporal Dead Zone)TDZ:(let在定义变量之前进行访问变量时所引起的现象):

在let声明变量前,使用该变量,它是会报错的,而不是像var那样会‘变量提升’。
其实说let没有‘变量提升’的特性,不太对。或者说它提升了,但是ES6规定对用用let定义的变量:在执行let声明语句前,不能使用该变量。这种语法叫做暂时性死区
ES6 规定暂时性死区和 let、const 语句不出现变量提升,主要是为了减少运行时出现错误,防止在变量声明之前就使用这个变量,从而导致意料之外的行为。
总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。具体可以看下面的代码调试截图

在这里插入图片描述

参考截图1

这里是引用

参考截图2:

在这里插入图片描述

参考截图3:

在这里插入图片描述

<script> 
             var a1=3;
            console.log('hhhhh')
            if(true){ //块级作用域
                console.log('jjjjj')
            
                let a4;
                console.log(a4);//undefined(不会报错!!!!!)
                console.log(a3);//undefined
                console.log(a2);//undefined
                console.log(a1); //报错 Uncaught ReferenceError: Cannot access 'a1' before initialization(在初始化之前无法访问“a1”)
                let a1=4;
                var a2;
             }
             var a3=1
     </script>

在这里插入图片描述
断点调试上述代码,当刚进入if中时,右侧出现Block(代表块级作用域),可以看见此时已经有a1、a4,但是上面代码仍旧报错了,而不是输出undefined。因为此时不可访问(暂时性死区)。

在这里插入图片描述

<script> 
       let a=10;
       function sing(){
          //函数作用域
          console.log('jjjj');
          console.log(a) //报错,因为必须要执行过初始化语句后才能访问。
          let a=9;
          function hh(){
              var b;
              console.log(a);
         }
         hh();
       }
       sing();
</script>

在这里插入图片描述

在这里插入图片描述

(3)脱离全局作用域,并未脱离函数作用域

在全局作用域中使用 let 、const声明的变量,将不会绑定在全局作用域 window 或是 global。也不会成为window的属性。

<script> 

           var a1=4;
           let a2=9;
           const a3=8;

           console.log(a1);//4
           console.log(a2);//9
           console.log(a3);//8
           console.log(window.a1);//4
           console.log(window.a2);//undefined
           console.log(window.a3);//unedfined
</script>


当代码执行第16行时,注意右边scope下有两个作用域:一个是scipt,一个是Global。

在这里插入图片描述


函数作用域中不像全局作用域中会出现script。

 <script> 
			//function中无script。函数作用域中不像全局作用域中会出现script。
           function sing(){
               console.log('jjjjj');
               let a=9;
               if(true){
                    let a=9;
                    console.log(a);
                }
               
           }
           sing();
 </script>


当代码进入函数内部,执行第13行代码时:看右侧Scope区域。

在这里插入图片描述

当代码执行到第16行(第16行还未执行)时,看右侧Scope区域。

在这里插入图片描述

3.const

与let声明变量的区别是,const声明的是常量,声明时就必须进行初始化。其值一旦被设定后不可更改。其余与let相同。

在这里插入图片描述

在编写程序过程中,如果存储的数据不需要变化,则用const。因为js解析引擎不需要实时监控值的变化,效率比较高,所以使用const关键字比let关键字好。

<script> 
        console.log('hhhh')//不会执行。
        const a;//声明时未初始化,报错
        a=9;
</script>

在这里插入图片描述


4.三者对比
三者区别

(1)其是否会挂载到window上
var声明的全局变量会挂载在window上,而let和const声明的全局变量不会挂载到window上,它形成了一个块作用域

这里是引用
(2)是否存在变量提升
var声明变量存在变量提升,let和const不存在变量提升
(3)暂时性死区
let 和 const 定义的变量在执行声明语句之前调用,会抛出错误(形成了暂时性死区),而 var 不会。
(4)是否一旦声明,必须立即初始化赋值
var 和 let 声明的时候可以不初始化赋值,const声明时必须赋值。
(5)同一作用域下是否可以重复声明
同一作用域下let和const不允许重复声明,否则会报错,而var可以
(6)是否可以修改
var和let可以可以修改声明的变量,const不可以。
const 声明的是一个只读的常量。一旦声明,常量的值就不能改变( 如果声明的常量是一个对象的话,那么不能改变的是对象的引用地址)
(7)是否有块作用域
let和const有块作用域,var没有块作用域。

5.let解决for循环问题

<script> 
      var funcs = [];
      for(var i=0; i<4; i++) {
          funcs.push(function(){
              console.log(i);
          });
      }

      funcs.forEach(function(func) {
          func();  // 输出4次数字4
        });
</script>

为了解决上述问题
方法1:直接将for循环中var改成let即可
方法2:使用立即调用函数表达式(IIFE)/闭包

方法1:直接将for循环中var改成let即可

在这里插入图片描述

在这里插入图片描述

 方法2:使用立即调用函数表达式(IIFE)/闭包

<script> 

        var funcs = [];

        for(var i=0; i<4; i++) {
            funcs.push((function(value){
               return function(){
                   console.log(value);
               }
            }(i)));
        }

        funcs.forEach(function(func) {
            func();  
        });
 </script>

在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值