01.JS块级做用域与let

1.块级做用域
   什么是:
         在一个代码块(括在一对花括号中的一组语句)中定义的所需变量(与let配合使用)并在代码块的外部是不可见的。
   为何:
         在ES6以前,函数只能在全局做用域和函数做用域中声明,不能在块级做用域中声明,形成诸多问题:
              1.内层变量会覆盖外层变量
              2.用来计数的循环变量泄漏变成全局变量
   什么时候:
         须要强化对变量生命周期的控制,避免全局污染出现错误
   优势:
         1.阻止变量泄漏变为全局变量,形成全局污染
         2.阻止变量提高覆盖
         3.内层做用域能够定义与外层做用域相同的变量名,但变量是独立的。
         4.容许任意嵌套,外层做用域没法读取内层做用域的变量
   块级做用域:
         {},if{},else{},while{},for{},swicth{}…函数

    //块级做用域{},与let配合使用
    {
      //大括号之间就是块级做用域
      var num=1;//仍是全局变量,能够被外部访问
      let num=1;//局部变量,不能够被外部访问,块级做用域必须用let声明
    }
    console.log(num);//此时num已经不能够被访问,说明块级做用域生效

    //内层做用域能够定义与外层做用域相同的变量名,容许任意嵌套
    //但变量与变量之间是没有关系的,都是独立的个体。
    {
      let aa=1;
      console.log(aa);//1
      {
        let aa=11;
        console.log(aa);//11
        {
          let aa=111;
          console.log(aa);//111
        }
      }
    }
    console.log(aa);//此时是不能被访问的,防止aa泄露为全局变量

    //防止变量提高形成覆盖
    //虽然都是f,可是配合了let使用,{}内部变成了一个小个体,不会影响其余的f
      var f=17;
      {
        let f=28;
        console.log(f);
      }
      console.log(f);

    //for块级做用域
    //计算1-100之间全部的整数的和,使用var声明
    for (var i=1,sum=0;i<=100;i++){
      sum+=i;
    }
    console.log(sum);//5050,能够访问
    console.log(i);//101,能够访问

    //使用let声明变量
    for (let i=1,sum=0;i<=100;i++){
      sum+=i;
    }
    console.log(i);//此时i是不能被访问的。
    console.log(sum);//此时sum是不能被访问的。
    //根据需求得知,最后须要访问的是sum,i须要释放
    //因此把sum单独放在外面,sum就能够被访问,而i会被释放
    var sum=0;
    for (let i=1;i<=100;i++){
      sum+=i;
    }
    console.log(sum);

2.let声明
   什么是:
         专门代替var来声明变量用的
   为何:
         var的问题:
             1.声明提早
             2.没有块级做用域
             3.形成全局污染
   什么时候:
         只要声明变量都用let
   优势:
         1.阻止了声明提早
         2.添加了块级做用域
         3.成为局部变量,不会形成全局污染
   原理:
         let其实就是一个匿名函数自调用!
         且let为了双保险,其实在底层悄悄给变量改了名字,在变量前增长了_
   let的小脾气:
         1.在相同做用域/块内:禁止同时let两个同名的变量
         2.在let 变量 以前到当前做用域的顶部之间,不容许提早使用变量
         3.不能够在函数内部重复声明参数spa

    //1.简单了解let声明的变量
    let a=2;
    console.log(a);
    let a=3;
    console.log(a);//报错,a不能重复声明并赋值

    //var声明的变量能够重复声明并从新赋值
    var b=2;
    console.log(b);//2
    var b=3;
    console.log(b);//3

    //在块级做用域内{}
    {
      var c=2;
      let c=4;//在同一块级做用域内不容许重复声明变量
      let d=3;
      console.log(d);//只能在当前{}块级做用域内访问
    }
    console.log(c);//能够被外部访问的是var声明的c
    console.log(d);//不能够被外部访问

    //let不容许先调用,后声明
    {
      console.log(aaa);
      let aaa=5;//报错Cannot access 'aaa' before initialization
    }

         把let放入实例中理解日志

        //let应用
        //累加每一个任务函数的时间
        var t=0;
        function task1(){
            console.log(`任务1耗时3s`);
            t+=0.3;
        }
        function task2(){
            console.log(`任务二耗时8s`);
            t+=0.8;
        }
        task1();
        task2();
        console.log(`共耗时${t}s`)
         以上是一个能够正常执行的代码,而且是正确的程序
         若是在task2内添加其余的功能,例如捕捉错误
        //累加每一个任务函数的时间
        var t=0;//声明变量t准备累加每一个任务函数的时间
        function task1(){
            console.log(`任务1耗时3s`);
            t+=3;
        }
        function task2(){
            console.log(`任务二耗时8s`);
            t+=8;
            //模拟出错的变量,此段代码是不执行的
            var err=false;
            //若是出错
            if(err==true){
                //就得到出错时间
                var t=new Date();
                //并输出出错提示日志
                console.log(`出错啦,at:${t.toLocaleDateString()}`);
            };
        }
        task1();
        task2();
        console.log(`共耗时${t}s`)
         代码正常执行,if内代码是不执行的,可是结果倒是错误的,少了8s,那么为何少了8s呢?
         原来是由于var声明的变量是全局变量,而if{}不是做用域,没有实体墙,拦不住var,
         因此var声明的变量会提高到当前做用域task2的最前面。
        //累加每一个任务函数的时间
        var t=0;//全局t
        function task1(){
            console.log(`任务1耗时3s`);
            t+=3;
        }
        function task2(){
            //var t;//undefined,var声明的t提早到该做用域最前面,而且没有赋值
            //若是task2()中已经有了局部变量t,就不会用全局的t了,只有在局部没有的t的时候才会调用全局的t
            console.log(`任务二耗时8s`);
            //这个8s没有加到全局t,而是加在局部t上,当函数调用后,局部的t就被释放了
            t+=8;//task2中的局部变量t,加在这里
            var err=false;//模拟出错的变量
            //若是出错
            if(err==true){//if else for while do whlie 等程序结构的{}不是做用域,不是实体墙,拦不住var
                //就得到出错时间
                var t=new Date();
                //并输出出错提示日志
                console.log(`出错啦,at:${t.toLocaleDateString()}`);
            };
        }
        task1();
        task2();
        console.log(`共耗时${t}s`)//此处输出的是全局的t,因此没有那8s,
         那么鉴于这种明明没有执行的代码,却破坏了本来正确的代码,
         这就是没有块级做用域带来的危害,此时就须要使用let声明变量了,
         由于let会阻止声明提早,并会添加块级做用域
       //累加每一个任务函数的时间
        var t=0;//全局t
        function task1(){
            console.log(`任务1耗时3s`);
            t+=3;
        }
        function task2(){
            console.log(`任务二耗时8s`);
            t+=8;//这个t仍是会加到全局的t上,没有被影响
            //模拟出错的变量
            //var err=false;//代码不执行
            var err=true;//代码执行
            //若是出错
            if(err==true){//let将if{}也变成了一级做用域,这个做用域是有实体墙的,是能够拦住let声明的变量的                //就得到出错时间
                //let阻止了局部的t被声明提早
                let t=new Date();//此时的t是在这个if块级做用域的函数内,不会存在提高
                //并输出出错提示日志
                console.log(`出错啦,at:${t.toLocaleDateString()}`);//因此此时输出的t也是if内的t
            };
        }
        task1();
        task2();
        console.log(`共耗时${t}s`)//打印全局t
         let的原理,添加匿名函数自调用,并改变名字
        //累加每一个任务函数的时间
        var t=0;//全局t
        function task1(){
            console.log(`任务1耗时3s`);
            t+=3;
        }
        function task2(){
            console.log(`任务二耗时8s`);
            t+=8;//这个t仍是会加到全局的t上,没有被影响
            //var err=false;
            var err=true;//模拟出错的变量
            //若是出错
            if(err==true){//let将if{}也变成了一级做用域,这个做用域是有实体墙的,是能够拦住let声明的变量的
                //(function(){//let自动添加的
                //就得到出错时间
                //let阻止了局部的t被声明提早
                let t=new Date();//let悄悄改变了名字,变成了_t,此时的t是在这个if块级做用域的函数内,不会存在提高到
                //并输出出错提示日志
                console.log(`出错啦,at:${t.toLocaleDateString()}`);//_t,因此此时输出的t也是if内的t
                //})();//let自动加的
            };
        }
        task1();
        task2();
        console.log(`共耗时${t}s`)//打印全局t    

         单词:
               declare——声明
               access——访问
               initialization——初始化——>第一次声明+赋值=初始化code

相关文章
相关标签/搜索