zoukankan      html  css  js  c++  java
  • 我的JavaScript笔记--数据类型,预编译,闭包

     在我们js中存储数据的空间可以分为两种,堆内存和栈内存
    堆内存:我们定义的那些引用数据类型的数据都会在堆内存中开辟空间。
    栈内存:我们运行的js代码还有我们定义的基本数据类型,都直接在栈内存中存储
    基本类型 Undefined ,Null ,Boolean ,Number,String 该五种类型在内存中占用空间,即
    值保存在栈内存中,可以提高查询变量速度,我们说他们是按值访问的
    引用类型
    引用类型,内存地址存在栈中,实际值存在堆内存。在堆内存中为这个值分配空间,因为这个值不确定大小,因此不能把它保存在栈内存中,因此把内存地址保存在栈内存中。
    预解释 1,在JS运行之前,先会找所有带var和function关键字的,先把她们声明 2,找完了,再从上到下执行js代码 3,function在等号右边,这个function不会预解释
    带function关键字的(就是定义函数),在整个脚本执行之前,就已经把函数名(其实就是变量名)在内存里安排好了,并且给这个函数名赋了值(就是函数体)
    function关键字定义的,会把function内容(名字和函数体)都加在栈内存中。
    //var a; //遇见var,先把a声明,分配地址。 即var=a;
    alert(a);
    var a=10;
    alert(a);
    ---------------------------------------------------------------------------------------
            fn();//1
            function fn() {
                //alert(arguments.callee); //arguments.callee 函数自己 function fn() { alert(arguments.callee); //arguments.callee 函数自己
                alert(1);
            }
            fn();
    带var和function的预解释是不一样的 1,var关键字是声明, 2,functions不仅声明了而且还定义了,它存储的是代码字符串没有任何意义
    预解释是发生在作用域下的,刚开始进来的时候,我们预解释的是全局作用域(Global),在js中我们的globe就是window。
    如果在当前作用域下的一个变量,没有预解释。就向他的上一级去找,直到找到window为止,如果window也没有定义,就被报错误。xxx is not defined
    function:我们运行函数的时候,会生成一个新的私有作用域(我们可以理解为开辟一个新的栈内存),在这个内存中,我们也要执行我们的预解释机制
    当我们的函数执行后,这个内存或者作用域就会被销毁。
    function的运行周期,一个function从window下的预解释的时就声明并定义了,当function执行的时候会产生新的作用域,当function执行完成,
    通常这个这个作用域会被销毁。
    预解释只发生在var 和 function 上。
       -------------------------------------------------------------------------------------------------------------------------------------------
      
           fn(); //报错 找不到fn
            var fn1= function fn() { 
                //alert(arguments.callee); //arguments.callee 函数自己 function fn() { alert(arguments.callee); //arguments.callee 函数自己
                alert(1);
            }
             fn(); //报错 找不到fn
                //预解释只会对等号左边有效果,所以这里fn1会预解释,但右边不会被预解释 相当于 fn1=function(){    函数体}
    -------------------------------------------------------------------
            var n = 9;
            var s = "str";
            function fn() {
                alert(n);
                alert(s);
                n = 7;
                s = "rts";
                var n = 6;
                alert(n);
            }
            fn();
            alert(n);
            alert(s);
    undefind  ,str ,6,9 , rts
    -------------------------------------------------------------------------------------------------------  
        <script>
            alert(a); // a is not defined
        </script>
        <script>
            var a = 1;
        </script>
        <script>
            alert(a);//1
        </script> 
    预解释只对当前脚本块中起作用
    -------------------------------------------------------------------------------------------------------
    alert(a);
    var a=12;
    var a;
    var a;
    alert(12);
    undefined  , 12
    ------------
    function a(){}
    var a;
    alert(a);
    弹出 function a(){} 因为function a也是预解释
    预解释不会在同一变量上重复发生。即var a=12;已经预解释,后面的var a不会在执行。
    --------------------------------------------------------------------------------------------------------
    alert (f);
    fn(); //没有预解释,所以报错
    var f=funcion fn(){ alert("ok");}
    undefind, fn is not defined
    系统找不到fn,所以调用fn会报错。
    JS只对等号左边带var 和 function 预解释 。等号右边是赋值,不会预解释。
    -------------------------------------------------------------------------------------------------------
            var a = 12;
            function a() {alert(1);}
            alert(a);
            a(); //a is not a function
    在项目中,切记不要让函数名和变量名相同
    function a和 变量 a (没赋值),function a会覆盖变量a      
      var a ;
            function a() {alert(1);}
            alert(a); //function a() {alert(1);}
            a(); //弹出1
    function a和 变量 a ( 赋值),变量a会覆盖function a
     var a = 12;
            function a() { alert(1); }
            alert(a); //弹出12
            a(); //a is not a function 
    --------------------------------------------------------------------------------------------------------
    alert(a);
    if(1==2)
    {
        var a=12;
    预解释是不受if获其他判断条件影响的。即使条件不成立,条件里只要有var或function也会被预解释。
    -----------------------------------------------------------------
    if(!("a" in window)){ var a= "珠峰培训";} 
    alert(a);
    //undefined 因为a在预编译中声明了
    ----------------------------------------------------------------
    我们的预解释也不会受到function的return影响
       function fn() { alert(1); };
            function fn2() {
                alert(fn);
                fn = 3;
                alert(fn);  
                return;
                function fn() { alert(2); }
            }
            fn2(); //function fn() { alert(2); }  -- 3
    定义一个function,如果我们只是return,没有返回任何东西外面接收的也是undefined。
    不加return,也是undefined
    -----------------------------------------------------------------
     var f=function fn(){ alert(); }
    //等号右边当成一个值,不会被预解释,所以系统找不到这个函数。 
    alert(typeof f); //function
    预解释,f是个变量
    function fn(){}
    预解释 fn是个function
    -----------------------------------------------------------------
    闭包:当我们的一个函数返回一个新的函数,我们在外面定义一个变量来接收,这样这个函数的内存就不能在执行完成之后自动销毁,也就是所谓的函数内存被占用了。(前提是我们返回的function里面有需要外面函数的东西)
    在函数总可以(嵌套)定义令一个函数时,如果内部的函数引用外部函数的变量,就会产生闭包
         闭包其实就是函数在运行的时候产生的那个私有作用域。
         闭包的作用说的更直白一些就是为了让变量更安全,让一个环境中的变量与其它环境中的变量隔离开不产生冲突
        闭包是形成的私有作用域 ,让内部的变量不受外部函数影响
      最外层的function内,内存被占用,得不到释放。                                      
    -------------------------------------------------------------------
            var n = 0;
            function a() {
                var n = 10;
                function b() {
                    n++;
                    alert(n);
      }
                b();    
                return b;
            }
            var c = a();
            c();
            alert(n);
    11
    12
    0
    相当于
             var n = 0;
            function a() {
                var n = 10;
                return function () {
                    n++;
                    alert(n);
                }
            }
            var c = a();
            c();
            c();
    ----------------------------------------------------------------------
            var n = 99;
            function ourer() {
                var n = 0;
                return function inner() {
                 return n++; //return 直接返回的那个,其实是一个结果或者是值,是不需要预解释的。
                //this.n++;
                }          
            }
            var c = ourer();
    //var c=funciton inner(){return n++;} 直接去上一级找,n=0  this.n=99
            var num1 = c(); //0
            var num2 = c(); //1
            alert(num1);
            alert(num2);
     
     -------------------------------------------------------------------
    ;()();
    ;(funtion(){         函数体   })();
    如果我们想要在闭包中使用我们的全局变量
    1,传参数
    2,window
    3,私有作用域下声明同名的变量
    --------------------------------------------------------------
    this只存在于function中
    this表示谁,由当前调用这个方法的主体来决定
    this关键字和在哪个作用域下执行也没关系,和调用的主体有关系
    就看这个点前面是什么,什么都没有就是window。
           var point = {
                x: 10,
                y: 20,
                moveTo: function (x, y) {
                    var moveX = function (x) { this.x = x; }
                    var moveY = function (y) { this.y = y; }
                    moveX(x); //主体是window
                    moveY(y);
                }
            }
            point.moveTo(100, 200);
            alert(point.x);//10
            alert(point.y);//20
            alert(x);//100
            alert(y); //200
    -----------------------------------------------------------------------------------------------------------------------
    var number=2;
    var obj={
         number:4;   
                 fn1:(funciton(){        //在这样一个闭包内,this指向window
                this.number*=2;        //这个this 是window
                number=number*2;   //迷惑人
                var number=3;
                    return function(){
                                this.number*=2;
                                number*=3;  //指向外面的那个number=3 
                                alert(number);
                        }
                         })()
     }
    var fn1=obj.fn1;             
      //fn1=     function(){
      //                           this.number*=2;
      //                          number*=3;  //指向外面的那个number=3 
      //                          alert(number);
      //                  }
    alert(number);//4
    fn1();                //alert(9);              window.number=4,    
    obj.fn1();         
                       //      function(){        
                       //         this.number*=2;
                       //         number*=3;  //指向外面的那个number=3 
                       //          alert(number);
                       //    }()          this.number=obj.number*2=8     alert(27)                window.number=8,    
    alert(window.number);
    alter(obj.number);
    ---------------------------------------------------------------------------------
    具体的应用实例:
    有如下html代码,要求:点击下面的li,会弹出对应的索引号。
    <ul>
    <li>列表一</li>
    <li>列表二</li>
    <li>列表三</li>
    <li>列表四</li>
    <li>列表五</li>
    </ul>
    很多人给出了如下错误的代码(点击li时弹出的是5):
    <script>
    var oLis=document.getElementsByTagName('li');
    for(var i=0; i< oLis.length; i++){
      oLis [i].onclick=function() {
    //注意:这里的这个匿名方法,在循环运行的时候这个匿名方法本身并不运行,当点击某个li的时候,这个方法才运行呢。
        alert(i);
    //这里的这个i不是在这个匿名方法里定义的,而是上一级作用域里定义的。当这句代码运行的时候,循环早已经结束,并且i已经等于oLis.length了。
    这里的问题出在这个方法里用到的是上一级作用域里定义的变量,如果要解决这个问题。
      };
    }
    ps:个人理解,这里面i是个全局变量,所以点击触发的时i已经不是绑定时的值了
        
    //事件绑定相当于做计划,当点击的时候才相当于执行计划,请参考第一天教材的事件绑定部分的描述
    </script>
    正确的代码一:
    <script>
    var oLis=document.getElementsByTagName('li');
    for(var i=0; i< oLis.length; i++){
    ;(function(i){//这里的这个i,已经不是外面的那个i变量了。
      oLis [i].onclick=function() {      alert(i);   };
    })(i);
    }
    </script>
    把上面的代码分解一下:
    当第一次循环运行的时候,i的值为0,则实际运行的代码如下:
    ;(function(i){//这里的这个i,已经不是外面的那个i变量了。
      oLis [i].onclick=function() {      
         alert(i); 
      };
    })(0);//因为i第一次是0,那么这里就相当于把0做为实参传给这个要运行的匿名函数,当这个匿名函数运行的时候,实际执行的就是这句代码了:
    oLis [0].onclick=function() { 
       alert(0);
    };//alert里已经是一个具体的数值了,第一次是0,依次是1234
     
    正确代码二:
    <script>
    function  fn(i){                 
    oLis [i].onclick=function() {  alert(i);   };    
     }
    var oLis=document.getElementsByTagName('li');
    for(var i=0; i< oLis.length; i++){      
      fn(i);      //相当于在fn()里形成私有作用域,相当于形成闭包
     }
    </script>
    var m=999;
    function fn(){
    var n=m=i=9;
    }
    alert(m); //999
    这里面,m和i是全局变量
    ----------------------------------------------------------------------
      var a=1;
      if(!"a" in window)
      {
           alert(a);
          var a=2;
      }
    undefined //没有弹出
     var a=1;
      if("a" in window)
      {
           alert(a);
          var a=2;
      }
    弹出1

    如果你觉得我的文章对您有帮助,给点鼓励,谢谢

  • 相关阅读:
    模拟赛QAQ
    复习计划
    luogu P1080 国王游戏
    [NOIP2012T3]开车旅行
    luogu P1967 货车运输
    同余方程组的扩展欧几里得解法
    luogu P1476 休息中的小呆
    GRYZY #13. 拼不出的数
    GRYZY- #10. 财富
    GRYZY #8. 公交车
  • 原文地址:https://www.cnblogs.com/aqbyygyyga/p/9843705.html
Copyright © 2011-2022 走看看