DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> JavaScript基礎知識 >> 關於javascript面向對象之閉包
關於javascript面向對象之閉包
編輯:JavaScript基礎知識     

學習javascript一段時間了,經過師傅的指引,自己對閉包作出如下總結,如有某點不妥,請君指出,不勝感激!

要理解閉包,首先必須理解Javascript特殊的變量作用域。

變量的作用域無非就是兩種:全局變量和局部變量。

Javascript語言的特殊之處,就在於函數內部可以直接讀取全局變量,而在函數外部無法讀取函數內的局部變量。

注意點,函數內部聲明變量的時候,一定要使用var命令。否則變為全局變量。

簡而言之,閉包就是一個受到保護的變量空間。

閉包案例

functon(){
  var num = Math.random;
  return num;  

}
var res = foo();
在這不能直接訪問函數內部變量num,只可以間接訪問


var r1 = foo();
var r2 = foo();
alert(r1 + '\n'+ r2);
如果使用return返回函數內的數據,理論上不是訪問一個數據,
因為在函數運行會分配內存空間,函數調用的時候,數據也會再次創建

若要解決以上問題,獲得相同的數據如何操作

function (){
  var num = Math.random();
  return  function (){

   return num;
     }  

}   

var fn = foo();//函數調用一次num就是唯一的
var r1 = fn();
var r2 = fn();
alert(r1 + '\n' +r2)
//fn是在一個在函數內定義的函數,那麼在執行時候可以訪問到上一級作用域中的num ,
 因此在最外面,就可以間接訪問唯一的num。此處就是用到了閉包,此次起到保護數據的我作用

 

函數的本質:Function的實例,也是對象。

執行一個函數,讓函數返回對象

function Foo(){
 var o = {num: 123};
 return o;
}
var obj = Foo();
alert(obj.num);//123

在調用函數時,函數內部創建一個對象

o中存儲著對象的引用,return是將o中的數據拷貝一份再返回

返回的結果被obj接收,此時obj存儲的是對象的引用

執行一個函數,讓函數返回一個函數

 

function Foo(){
 var o = new Function('alert(123)');
 return o;
}
var fn = Foo();
相當於var fn = new Functon('alert(123)');
alert(fn);//123


執行一個函數,讓函數返回一個數組

function func(){
  var m = Math.random();
  var n = Math.random();
  return [
        function () { return m;}
        function () { return n;}
    
      ]
}
// var fns = func();
// var m1 = fns[0](); 
// var n1 = fns[1]();  
// alert(m1 +','+ n1) ;  

// var m2 = fns[0](); 
// var n2 = fns[1]();  
// alert(m2 +','+ n2) ; 

 

在以上兩組數據中輸出的結果是相同的,

數組的優點體現出數據的有序性 多個數據可以進行排序

但是在復雜數據中,數據的序號就不再有優勢

可以用對象對以上函數改進

function func(){
  var m = Math.random();
  var n = Math.random();
  return {
     get_M: function (){ return m;},
     get_N: function (){ return n;} 
   };    
}
// var obj = func();
// var m1 =obj.get_M();
// var n1 = obj.get_N();  
// alert(m1 +','+ n1) ;   

閉包案例之調用一函數提供兩個方法,對num進行賦值和讀取
第一種寫法

function Foo(){ 
     var obj = new Object(); //這裡也可以寫成 var obj = {};??
     var num;
     obj.get_num = function(){
      return num;
};
     obj.set_num = function(v){
     num = v;

};
    return obj;

}  
var o = Foo();
console.log(o.get_num());//undefined
console.log(o.set_num(11));//undefined
console.log(o.get_num(11));//11

第二種寫法

function Foo() {
                var num;
                return {
                    get_num: function () {
                        return num;
                    },
                    set_num: function ( v ) {
                        num = v;
                    }
                };
            }        
            var o = Foo();        
            console.log( o.get_num() );    //undefined
            console.log(o.set_num( 11 ));//undefined        
            console.log( o.get_num() );//11


這有一個對以上函數的變式

function Foo() {
                    var num;
                return {
                    _num: num,//賦值操作
                    set_num: function ( v ) {
                        num = v;
                    }
                };
            }
            //相當於下面函數
            function Foo() {
                var num;
                var obj = {};
                obj._num = num;//上面聲明的num和此時的_num變量是不同的
                obj.set_num = function ( v ) {
                    num = v;
                };
                return obj;
            }
            
            var o = Foo();        
            console.log( o._num );  //undefined          
            console.log(o.set_num(11));  //undefined          
            console.log(o._num);  //undefined   取不出數據


閉包的應用:實現私有數據和緩存數據

閉包案例之斐波那契數列

沒使用閉包的函數式

var count = 0;
    var fib = function (n){
        count++;
        if(n< 0)throw new Error('不允許出現負數');
        if(n === 0||n === 1)return 1;
//        return fib(n-1)+fib(n-2);
        return arguments.callee(n-1) + arguments.callee(n-2);     
    }

    console.log(fib(16));
    console.log(count);
    //分別計算第1、2、4、8、16、32項對應的次數為1、3、9、67、3193、7049155

從以上計算的次數可以看出性能的損耗很嚴重,那麼閉包可以在此解決的問題是已經運算過得數據緩存下來

var count = 0;
    var fib = (function(){    
        var arr = [];
        return function (n){
            count++;
            if(n < 0)throw new Error('不允許出現負數');
            var res = arr[n];//緩存數據 判斷有無數據
            if(res !== undefined){
                return res;
            }
            else {
                    if(n === 0||n ===1) {
                        res = 1;
                    }
                    else{
                    res = fib(n - 1)+fib(n - 2);
                    }    
                }
            arr[n] = res;
            return res;
            }
    })();
    console.log(fib(100));
    console.log(count);//199

第二種寫法

var count = 0;
    var fib = (function(){
        var arr = [];
        return function(n){
            count++;
            return    feibo(arr,n);
        }
    })();
    function feibo(arr,n){
        if(n < 0)throw new Error("不允許出現負數");
        var res = arr[n];
        if(res != undefined){
            return res;
        }else{
            if(n === 0 ||n === 1){
                res = 1;
            }else{
                res = fib(n - 1) + fib(n - 2);
            }
        }
        arr[n] = res;
        return res;    
    }
    console.log(fib(100));
    console.log(count);


從上式可以看出閉包帶來的好處;

拓展:談到數據緩存也可以不用閉包,下面函數則與閉包無關

var fib = function ( n ) {
                var res = fib[ n ];   // 先到函數名中取
                if ( res !== undefined ) {
                    return res;
                } else {
                    // 如果是 1 或 0 則將 1 返回給 res
                    // 否則遞歸結果交給 res;
                    
                    if ( n === 0 || n === 1 ) {
                        res =  1;
                    } else {
                        res = arguments.callee( n - 1 ) + 
                                arguments.callee( n - 2 );
                    }
                    
                    fib[ n ] = res; 
                    // 將計算的結果放到數組中, 那麼下一次再計算的
                    // 時候可以直接拿來用, 就不用重新計算
                    fib.len++;//每次賦值完後                    
                    return res;
                }
            };        
            fib.len = 0;//給函數添加一個屬性        
            console.log(fib(100));
            console.log(fib.len)//101
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved