从入门到放弃第二天:作用域与闭包

641 阅读5分钟

目录:

  1. 什么叫作用域

  2. 作用域嵌套

  3. let块作用域

  4. 闭包

什么叫作用域

<script>或者<script>引入里面的属性都叫全局作用域!

作用域有:

  • 全局作用域

    1.所有的全局作用域都是互通的

    2.全局作用域就像一个盒子包袱住所有的变量语义一样;

    无标题

    从上到下读取排序;黑色是外边框是我们的全局变量包括住的属性

    var是ES5里面的声明变量,他具有全距变量的功能

    var会挂载到window属性里面,window里面属性非常多!

    会影响到window里面的属性!非常不友好!

    为了减少var变量声明影响到windo我们进入到函数作用域

    ES6方法里面let conse不会挂载到window里面哦

  • 函数作用域

    1.声明函数会挂载到windo对象里面!要避免以window冲突应该写自调用

    ES5:
    (function(){
        var a = 1;
        function Yan(){
           	console.log(1);//属性
        }
    })();
    console.log(window); //找不到 Yan属性 与 var变量属性了
    
    ES6:
    {
         var a = 1;
        function Yan(){
           	console.log(1);//属性
        }
    }
    console.log(window); //找不到 Yan属性 与 var变量属性了
    

    以上两种都是为了函数作用域为了解决与window冲突问题所在;

    考虑到兼容问题,IE建议ES5属性;


    函数作用域内声明的变量,只能他自己使用!外部不能访问!

    函数里面都有自己独立的作用域

    外层函数嵌套内层函数,作用域是包含关系.

  • 作用域嵌套

    全局变量作用域的变量,都可以访问到但是,内层作用域的变量外层无法访问

    
    //子级作用域可以访问父级作用域
    function zhu(){
        var a = 3;
        console.log(a);//3
        function Yan(){
            console.log(a);//3
        }
        Yan() // 3
    }
    zhu( );//3
    ------------------------------------------------------------------- 
    //这样看来, 子级作用域也可以访问到全局作用域
     var a = 4  
    function zhu(){
        console.log(a);//4
        function Yan(){
            console.log(a);//4
        }
        Yan() 
    }
    zhu( );
    -------------------------------------------------------------------
    // 哦买噶!报错了 因为 父级不能访问子函数;
    function zhu(){
        console.log(a);//报错
        function Yan(){
            var a = 4;
        }
        Yan() 
    }
    zhu( );//报错了.
    

    我们来看一个图:

作用域规则

  • 搜索规则:子函数(本地) > 父函数(封闭) >全局 从里到外 一层层的来读取;
  • 作用域,只看声明环境,不看执行环境

好!我已经告诉你 作用域规则了那么评论区告诉我这个答案是多少;

  • 提示引导:跟包含关系有相关

function fn( ){
    var a = 1;
    console.log(a);//1
    Yan() //调用 Yan
}
fn();//启动fn
function Yan(){
    console.log(a);??
}

嘿嘿嘿 不知道也没关系的,我后面在解答这个问题;


let块作用域~

  • 作用域当然是外部不能访问咯;

    假设HTML里面定义了五个li标签;

    //循环遍历一下 会发生什么吧
     const li = document.querySelectorAll("li");
        for (let index = 0; index < li.length ; index++) {
           li[index].onclick= function(){ //点击一次就会 触发一次
                alert(index);// 0,1,2,3,4
           }     
        }
    console.log(index);//报错;
    

    我们看一下 for循环里面的let是什么运行的

    • let给每个li赋值每一个的值 从0开始,当然var也可以;
    • 但let 给每个li创建了一个作用域!=W=
  • 可以看出 let 另外给li开创了五个块作用域

    • 并且外部是不能访问let块作用域
  • 因为作用域规则从里访问到外,而不是从外访问到里规则;

答案区:

function fn( ){
    var a = 1;
    console.log(a);//1
    Yan() //调用 Yan
}
fn();//启动fn
function Yan(){
    console.log(a);//报错
}
  1. 两个都是全局声明:达成并级状态
  2. 在里面执行而已,不能成为他的作用域!
  3. 两个函数是不可以互相访问的,只能执行;
  4. 所以上面已经报错了

闭包:

闭包条件了解一下?

  • 条件:函数 嵌套 函数
  • 内部函数 使用 外部函数的变量或者参数;
  • 闭包的作用是存值;并在相同作用域里调用
  • 并且用return返回出来

我们来了解一下《 JavaScript语精粹》:

JavaScript中函数运行在它们被定义的作用域里,而不是它们被执行的作用域里;

上面那句话多读几次就懂了

我们来创建一个闭包吧!

先在body创建script;哈哈哈开玩笑开玩笑 来正题;

创建一个函数 我定义名为 Yan

function Yan(){
    
};

在函数里面 加入属性

  • 我们已经知道 闭包条件了
  • 函数嵌套函数
  • 并且用return返回出来

所以我们嵌套个函数 定义名为 Chi()return出来;

function Yan(){
    var a = 1;//定义A 为了后面测试的闭包
    return function chi(){
        a++;//内部函数
  		console.log(a);
  }
};

我们让闭包的值,外部定义个变量,我们把变量定义为 b

function Yan(){
    var a = 1;//定义A 为了后面测试的闭包
    return function chi(){
        a++;//内部函数
  		console.log(a);
  }
};

let b = Yan();//调用的变量;
b();//调用了b,chi()里的a++启动了 所以 a = 2;
b();//再次调用 b chi()里的a++ 再次启动! 注意! 此时a变成2了; a=2 ++ ; a = 3;
//所以可以知道,闭包是可以保存值的;程序关闭后才消失;

当然 闭包使用参数也是可以的

function zhu(e){
  return function zhu1(){
     e++;
     console.log(e);
 }
};
var a = zhu(2);
a();//3
a();//4

我们再来一个闭包案例!

我把这个案例叫 bb赖赖ATM;

百因必有果,你的报应就是我;

记得点赞赞 么么哒;

function money1() {
  var ATM = {
   //一开始的钱  
    money: 100
  };
  return { //对象里面
    //add存钱
    add: function() {
      ATM.money += 10; //每次存钱的次数;
      console.log(`您存了10元后当前余额${ATM.money}`);
    },
     //lost消费
    lost: function() {
      ATM.money -= 5; // 每次消费5元;
      console.log(`您消费了5元 您当前的余额${ATM.money}`);
    },
    //get查询金额 
    get: function() {
      console.log(`您当前的余额${ATM.money}`);
    }
  };
    
let b = money1();//把值存在 b里面 每次调用 b;
b.get(); // 本身余额:100;
b.lost();// 消费 -5 :95;
b.add();//存10;+10;105;
/* 这样就可以成为了存放值的闭包 */   

闭包总结:

  • 可以存值, 作用域 变量;

  • 缺点:保存的变量或者参数 永久保存; 程序关闭之后才消失

    在IE情况下出现问题;

有什么感觉可以评论区告诉我 或者私信提交建议;

如有不适,请勿喷,胆小。

如发现:内容有问题,或者作者写错内容,分析错了;

请大佬留言本24小时改善,打造一个良好的学习环境

谢谢看完的各位大佬,比心~