美文网首页
3.作用域和闭包

3.作用域和闭包

作者: 飞菲fly | 来源:发表于2017-08-08 20:30 被阅读112次

//------------------题目------------------------->
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

相关文章

  • 作用域和闭包

    目录 概述 作用域编译过程词法作用域全局作用域函数作用域 闭包循环和闭包闭包的用途性能 总结 概述 作用域和闭包一...

  • javaScript门道之闭包

    闭包的学习路径:变量的作用域 -> 闭包的概念 ->闭包的应用 1.变量的作用域 变量的作用域分为作用于全局和作用...

  • python基础-08-内置函数、作用域、闭包、递归

    python基础-内置函数、作用域、闭包、递归 1.常见的内置函数 2.函数内变量的作用域 3.内嵌函数和闭包 4...

  • 2023-01-12

    变量提升调用栈块级作用域作用域链和闭包 闭包 => 作用域链(词法作用域) => 调用栈(栈溢出) => 上下文...

  • 闭包(closure)

    ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...

  • 2018-01-07 关于javascript闭包和作用域的理解

    关于 javascript 闭包的一些思考 作用域 词法作用域 函数作用域 块作用域 闭包 什么是作用域? 作用域...

  • 3.作用域和闭包

    //------------------题目------------------------->1.说一下对变量提...

  • js作用域、闭包

    闭包 闭包作用 全局 局部 作用域链

  • 浓缩解读《JavaScript设计模式与开发实践》③

    三、闭包和高阶函数 3.1 闭包 3.1.1 变量的作用域 所谓变量的作用域,就是变量的有效范围。通过作用域的划分...

  • js闭包的理解

    什么是闭包 通俗的来讲,个人觉得闭包就是延长变量作用域的函数。众所周知js的作用域分为全局作用域和链式作用域。在函...

网友评论

      本文标题:3.作用域和闭包

      本文链接:https://www.haomeiwen.com/subject/bhsxrxtx.html