3.作用域和闭包

//------------------题目------------------------->
1.说一下对变量提升的理解

针对两个场景一个script、一个是构造函数中,它的变量的声明和定义
以及函数的声明都会被提前,放在前面,所以会导致我们有变量提升主观上的理解。(执行上下文的知识)

    *1、变量定义
    *2、函数声明(注意和函数表达式的区别)

2.说明this集中不同使用场景

     *1、作为构造函数执行
     *2、作为对象属性执行
     *3、作为普通函数执行
     *4、call apply bind

3.创建10个<a>标签,点击时候弹出来对应的序号

     var i ;
     for(i=0;i<10;i++){
         //自执行函数,就是不用调用,只要定义完成,立即执行的函数
         (function(i){
            //  函数作用域
              var a = document.createElement('a');
             a.innerHTML = i+'<br>';
             a.addEventListener('click',function(e){
                 e.preventDefault();
                 alert(i);//自由变量,要去父级作用域获取值
             });
             
             document.body.appendChild(a);
             
         })(i);
     }
   
   //闭包或者作用域使用的问题
4.如何理解作用域
    *自由变量
    *作用域链,即自由变量的查找
    *闭包的两个场景
5.实际开发中闭包的应用
   //闭包是作用域知识点的实际应用
   //闭包实际应用中主要用于封装变量,收敛权限\
   // 判断用户是不是第一次加载  
   function isFirstLoad(){
       
       //把存储数据的数据源存起来,其他外边拿不到   
       var _list = [];//变量前面有下划线,说明这个是私有变量
       return function(id){
           if(_list.indexOf(id) >=0){
               return false;
           }else{
               //_list这里是自由变量,要去它定义的父作用域去找
               _list.push(id);
               return true;
           }
       }
   }
   
    //使用
    var firstLoad = isFirstLoad();
    firstLoad(10); //true
    firstLoad(10); //false
    firstLoad(20); //true
    firstLoad(20); // false
   
   
    //在isFirstLoad函数外边,根本不可能修改掉_list的值

//*******************知识点*******************************
一、执行上下文

执行上下文.png
执行机制.png

范围:一段<script>或者一个函数
全局:变量定义、函数声明
【一段<script>会生成一个全局的执行上下文,执行之前先去
把变量定义、函数声明拿出来】
函数:变量定义、函数声明、this、arguments
**【针对一个函数,会出现一个函数执行上下文,函数执行之前

          先把函数中的变量定义、函数声明、this、arguments(函数
          中所有参数的集合)拿出来】**
          
    PS:注意‘函数声明’和‘函数表达式’的区别:
    
     【函数声明】:
        //如果这里执行fn();不会报错;
        /*这段程序执行之前会把声明的
        函数提到前面去,先声明出来,执行不会报错*/
        
         function fn(name){
           age = 20;
           console.log(name,age);
           var age;
          }
      【函数表达式】:
      (本质上执行的只是这个变量,并不是把函数声明提前了)
        //在这里执行fn1();会报错;
        /*所有var fn1,在执行之前不是个函数,在执行之前会把var fn1
        提到前面去,并且赋值成undefined,var fn1并没有去执行*/
          var fn1 =function(){};
           
           
  /*在执行第一行之前,会把所有的变量的声明和函数声明都拿出来*/
   // 写程序先定义会执行(增加代码可读性))
  eg. 1.
  /*
  全局函数作用域(会把变量的声明,和函数的声明挪到前面去,
  先声明了;函数的声明是把函数挪前面去了,变量的声明把变量挪
  前面去了,并且赋值undefined,占位)
  
  */
   console.log(a);//undefined
   var a = 100;
   
   eg.2.
   fn('zhangsan');//'zhangsan' 20
   function fn(name){
       
       /*都会把变量提前,都会把函数提前*/
       /*在函数执行之前,this、arguments已经确定了值*/
       console.log(this);//window
       
       /*["zhangsan",callee:function,
       symbol{symbol.iteareator}:function]*/
       console.log(arguments);
       
       age = 20;
       console.log(name,age);
       var age;
   }

二、this

1.this要在执行时才能确认值,定义时无法确认

      1.作为构造函数执行
      
      function Foo(name){
          //this = {};
         this.name = name; 
         //return this;
      }
      var f = new Foo("zhangsan"); 
      
     2.作为对象属性执行
     
     var obj = {
         name:"A",
         printName:function(){
            console.log(this.name);
         }
     };
     
     obj.printName();
     
      3.作为普通函数执行(this应该是window)
      
      function fn(){
          console.log(this);// this === window
      }
      fn();
      
      4.call apply bind
     /**call apply **/
      function  fn1(name,age){
          alert(name);
          console.log(this);//this就是第一个参数
      };
      
      /*执行fn1这个函数,用{X:100}当this,"zhangsan"
      当第一个参数*/
      fn1.call({X:100},"zhangsan",20);
      
      //会把后面的参数当数组来传递
      fn1.apply({X:100},['zhangsan',20]);
      
      /**bind**/
     var fn2 = function (name,age){
          alert(name);
          console.log(this);
      }.bind({Y:200});
      
      //没bind之前this是window;bind之后this是{Y:100}
      fn2('zhangsan',20);
      
      
      
      eg:
      var a ={
         name:'A',
         fn:function(){
             console.log(this.name);
         }
         
      };
      
      a.fn(); //this === a
      
      a.fn.call({name:'B'}); //this === { name :'B'}
      
      var fn1 = a.fn;
      // this === window; this.name是undefined或者其他值
      fn1(); 

三、作用域

1.JS没有块级作用域
2.只有函数和全局作用域

    //------ 无块级作用域--------------
    if(true){
        var name = 'zhangsan';
    }
    console.log(name); //zhangsan
    // 和把name在外边定义然后再if中赋值是一样的
    // 推荐写法:在外边定义然后再下面赋值
    var name;
    if(true){
      name = 'zhangsan';   
    }
    console.log(name);
    
    //---------- 函数和全局作用域--------------
    
    //这个a是全局的,谁都可以获取,谁都可以改(不安全)
    var a =100;
    
    function fn(){
        /*函数中定义,和外边是隔绝的,外边是改不了的;
          从外边得不到,也改不了,只能从函数里去用;
          防止自己的变量被污染,把所有变量都定义在一个大的函数里
        */
        var a =200;
        console.log('fn',a);//在函数范围内获取
    }
    
     console.log('global',a);
     
     fn(); // global: 100; fn :200

四、作用域链

(一个自由变量一直不断的往父级作用域去找,形成一个链式结构)
-- 哪个作用域定义了这个函数,这个函数父级作用域就是谁,和函数执行没有关系

       //作用域完整的使用形式、场景
        1.eg:
        var a =100;
        function fn(){
           var b =200;
          
        //当前作用域没有定义的变量,即“自由变量”
        /*函数体内没规定a是谁,但是打印a,就要向父级作用域
        找a,父级作用域是全局作用域,所以a就找到var a =100;
        函数父级作用域是什么,是函数定义的时候的父级作用域
        ,不是函数执行时候的作用域*/
           console.log(a);
           console.log(b);
      }
      
      fn();
      
      2.eg:
      var a =100;
      function F1(){
          var b =200;
          function F2(){
              var c = 300;
              console.log(a); //100 a是自由变量
              console.log(b); //200 b是自用变量
              console.log(c); //300
          }
          F2();
      }
      F1();

五、闭包(作用域链的具体应用)

闭包的使用场景:
1.函数作为返回值
2.函数作为参数传递(把函数传递到另一个函数中执行)

   eg:1.函数作为返回值 
   //F1 这个函数最终返回的是一个函数
   function F1(){
       
       /*F1作用域里面的a*/
       var a =100;
       
       /*
        返回一个函数;
       */
       return function(){
           /*
           a是自由变量,自由变量去父级作用域(F1)找;
           一个函数的父级作用域,是它定义时候的作用域,
           而不是执行时候的作用域
           */
           console.log(a);
       }
   }
   
   //把F1()赋值给f1,f1就是一个函数了
   var f1 = F1();
   
   /*是全局作用域里面的a*/
   var a =200;
   
    f1(); //100
    
    
    eg:2.函数作为参数传递
    
    function F1(){
        var a =100;
        
        //F1返回一个函数
        return function(){
            console.log(a);
        }
    }
    
    //把F1()赋值给f1,f1就是一个函数了
    var f1 = F1();
    
    function F2(fn){
        var a =200;
        
        fn();
    }
   
   F2(f1);//100
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容