文斌的博客

学无止境
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

我的JavaScript笔记--数据类型,预编译,闭包

Posted on 2018-10-24 15:26  文斌1988  阅读(134)  评论(0编辑  收藏  举报
 在我们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

 

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