关于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;}

    1. ]

    } // var fns = func(); // var m1 = fns0; // var n1 = fns1;
    // alert(m1 +’,’+ n1) ;

    // var m2 = fns0; // var n2 = fns1;
    // 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; }

    1. var o = Foo();
    2. console.log( o._num ); //undefined
    3. console.log(o.set_num(11)); //undefined
    4. console.log(o._num); //undefined 取不出数据<br />

    闭包的应用:实现私有数据和缓存数据
    闭包案例之斐波那契数列
    没使用闭包的函数式

    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);
    }

    1. console.log(fib(16));
    2. console.log(count);
    3. //分别计算第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;

    1. if ( n === 0 || n === 1 ) {
    2. res = 1;
    3. } else {
    4. res = arguments.callee( n - 1 ) +
    5. arguments.callee( n - 2 );
    6. }
    7. fib[ n ] = res;
    8. // 将计算的结果放到数组中, 那么下一次再计算的
    9. // 时候可以直接拿来用, 就不用重新计算
    10. fib.len++;//每次赋值完后
    11. return res;
    12. }
    13. };
    14. fib.len = 0;//给函数添加一个属性
    15. console.log(fib(100));
    16. console.log(fib.len)//101<br />