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.不可以在函数内部重复声明参数

    //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——初始化——>第一次声明+赋值=初始化

原文地址:https://www.cnblogs.com/oksana/p/12386357.html

时间: 2024-08-29 18:13:08

01.JS块级作用域与let的相关文章

JavaScript的作用;JS常见的三种对话框;==和===的区别;函数内部参数数组arguments在函数内部打印实参;JS的误区:没有块级作用域

JS:客户端(浏览器)脚本语言 弱类型 基于原型 事件驱动 不需要编译(直接运行) JS的作用:表单验证,减轻服务端的压力 添加页面动画效果  动态更改页面内容  Ajax网络请求 (一)常见的对话框 alert()对话框:该方法是window对象的方法,在浏览器中弹出一个对话框(该方法没有返回值)  prompt()对话框:2个参数,一个是浏览器提示信息,第二个是默认的输入框的值,返回值就是输入框的信息  confirm()对话框:在浏览器弹出一个对话框,用户只能选择正确或者取消,返回值对应为

js没有块级作用域

今天看一篇介绍ECMAscript6的博文时,看到let命令的时候突然有点蒙逼....... let命令:let用于变量声明,与var用法类似,但是let是一个局部变量,只在声明的代码块中有效. { let a = 10; var b = 20; } a // not defined b // 20 看到这我觉得这个块级作用域是函数作用域,但是块级作用域和函数作用域是不一样的,比如: function demo(){ var a=1; } console.log(a); a//not defin

js私有作用域(function(){})(); 模仿块级作用域

摘自:http://outofmemory.cn/wr/?u=http%3A%2F%2Fwww.phpvar.com%2Farchives%2F3033.html js没有块级作用域,简单的例子: for(var i=0;i<10;i++){ alert(i); } alert(i); for循环后的i,在其它语言像c.Java中,会在for结束后被销毁,但js在后续的操作中仍然能访问到i值,即for循环后的alert(i);会弹出数值i=10; js模仿块级作用域: (function(){

JS的块级作用域

今天带来的是 "对<你不知道的js>中块级作用域的总结" 分享: 1)用with从对象中创建出来的作用域只在with声明中而非外部作用域有效,同时可以访问已有对象的属性并将其添加到已有对象上 代码demo: var obj = { a:1, b:2, c:3 }; with(obj){ a=3; b=4; c=5; d=6; } console.log(obj);//3,4,5 2)try/catch 的catch分句会创建一个块级作用域,其中声明的变量仅在catch内部有

6个函数的output看JS的块级作用域

1. var output = 0; (function() { output++; }()); console.log(output); 函数对全局的output进行操作,因为JS没有块级作用域,所以output为1. 2. var output = 0; (function(output) { output++; }(output)); console.log(output); 函数传入output的值,但函数内只是对参数output做加一操作,没有对全局的output进行操作,所以outp

js没有块级作用域但有函数作用域

任何一对花括号中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域. 作用域永远都是任何一门编程语言中的重中之重,因为它控制着变量与参数的可见性与生命周期.首先我们理解两个概念:块级作用域与函数作用域. 什么是块级作用域呢? 任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域. 函数作用域就是定义在函数中的参数和变量在函数外部是不可见的. 大多数类C语言都拥有块级作用域,JS却没有.请看下文de

js模仿块级作用域

var i = 5; var i; alert(i); 当一个变量被声明赋值之后,如果再对其声明,则不会改变上一次赋值后的值,所以i的值还是5,只有重新赋值之后,才会改变,如: var i = 5; var i = 6; alert(i); i现在的值是6: JS中没有块级作用域,如果想要块级作用域的效果,可以进行模仿,如: (function () { for (var i = 0; i < 5; i++) { } })(); alert(i); //出错 这方法可以理解为把块级作用域放在一个

JS作用域与块级作用域

作用域永远都是任何一门编程语言中的重中之重,因为它控制着变量与参数的可见性与生命周期.讲到这里,首先理解两个概念:块级作用域与函数作用域. 什么是块级作用域呢? 任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域. 函数作用域就好理解了(*^__^*) ,定义在函数中的参数和变量在函数外部是不可见的. 大多数类C语言都拥有块级作用域,JS却没有.请看下文demo: //C语言 #include <stdio.h> void mai

js作用域链 js没有块级作用域

arguments和函数内定义的变量或函数->父级->下一个父级->.....->全局环境中的变量或函数 if(true){ var a=1; } console.log(a);js没有块级作用域, 变量a直接添加到当前的执行环境中.  java有块级作用域,if语句结束后会销毁if中定义的变量