個人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, 依次是 1 2 3 4
 
正確代碼二:
<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

 

若是你以爲個人文章對您有幫助,給點鼓勵,謝謝html

相關文章
相關標籤/搜索