javascript面向对象之闭包

学习javascript一段时间了,自己对闭包作出如下总结,如有某点不妥,请君指出,不胜感激!

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量,而在函数外部无法读取函数内的局部变量。

注意点,函数内部声明变量的时候,一定要使用var命令。否则变为全局变量。

简而言之,闭包就是一个受到保护的变量空间。

闭包案例

  1. functon(){
  2. var num = Math.random;
  3. return num;
  4.  
  5. }
  6. var res = foo();
  7. 在这不能直接访问函数内部变量num,只可以间接访问
  8.  
  9. var r1 = foo();
  10. var r2 = foo();
  11. alert(r1 + '\n'+ r2);
  12. 如果使用return返回函数内的数据,理论上不是访问一个数据,
  13. 因为在函数运行会分配内存空间,函数调用的时候,数据也会再次创建

若要解决以上问题,获得相同的数据如何操作

  1. function (){
  2. var num = Math.random();
  3. return function (){
  4.  
  5. return num;
  6. }
  7.  
  8. }
  9.  
  10. var fn = foo();//函数调用一次num就是唯一的
  11. var r1 = fn();
  12. var r2 = fn();
  13. alert(r1 + '\n' +r2)
  14. //fn是在一个在函数内定义的函数,那么在执行时候可以访问到上一级作用域中的num ,
  15. 因此在最外面,就可以间接访问唯一的num此处就是用到了闭包,此次起到保护数据的我作用

函数的本质:Function的实例,也是对象。

执行一个函数,让函数返回对象

  1. function Foo(){
  2. var o = {num: 123};
  3. return o;
  4. }
  5. var obj = Foo();
  6. alert(obj.num);//123

在调用函数时,函数内部创建一个对象

o中存储着对象的引用,return是将o中的数据拷贝一份再返回

返回的结果被obj接收,此时obj存储的是对象的引用

执行一个函数,让函数返回一个函数

  1. function Foo(){
  2. var o = new Function('alert(123)');
  3. return o;
  4. }
  5. var fn = Foo();
  6. 相当于var fn = new Functon('alert(123)');
  7. alert(fn);//123

执行一个函数,让函数返回一个数组

  1. function func(){
  2. var m = Math.random();
  3. var n = Math.random();
  4. return [
  5. function () { return m;}
  6. function () { return n;}
  7.  
  8. ]
  9. }
  10. // var fns = func();
  11. // var m1 = fns[0]();
  12. // var n1 = fns[1]();
  13. // alert(m1 +','+ n1) ;
  14.  
  15. // var m2 = fns[0]();
  16. // var n2 = fns[1]();
  17. // alert(m2 +','+ n2) ;

在以上两组数据中输出的结果是相同的,

数组的优点体现出数据的有序性 多个数据可以进行排序

但是在复杂数据中,数据的序号就不再有优势

可以用对象对以上函数改进

  1. function func(){
  2. var m = Math.random();
  3. var n = Math.random();
  4. return {
  5. get_M: function (){ return m;},
  6. get_N: function (){ return n;}
  7. };
  8. }
  9. // var obj = func();
  10. // var m1 =obj.get_M();
  11. // var n1 = obj.get_N();
  12. // alert(m1 +','+ n1) ;

闭包案例之调用一函数提供两个方法,对num进行赋值和读取
第一种写法

  1. function Foo(){
  2. var obj = new Object(); //这里也可以写成 var obj = {};??
  3. var num;
  4. obj.get_num = function(){
  5. return num;
  6. };
  7. obj.set_num = function(v){
  8. num = v;
  9.  
  10. };
  11. return obj;
  12.  
  13. }
  14. var o = Foo();
  15. console.log(o.get_num());//undefined
  16. console.log(o.set_num(11));//undefined
  17. console.log(o.get_num(11));//11

第二种写法

  1. function Foo() {
  2. var num;
  3. return {
  4. get_num: function () {
  5. return num;
  6. },
  7. set_num: function ( v ) {
  8. num = v;
  9. }
  10. };
  11. }
  12. var o = Foo();
  13. console.log( o.get_num() ); //undefined
  14. console.log(o.set_num( 11 ));//undefined
  15. console.log( o.get_num() );//11

这有一个对以上函数的变式

  1. function Foo() {
  2. var num;
  3. return {
  4. _num: num,//赋值操作
  5. set_num: function ( v ) {
  6. num = v;
  7. }
  8. };
  9. }
  10. //相当于下面函数
  11. function Foo() {
  12. var num;
  13. var obj = {};
  14. obj._num = num;//上面声明的num和此时的_num变量是不同的
  15. obj.set_num = function ( v ) {
  16. num = v;
  17. };
  18. return obj;
  19. }
  20.  
  21. var o = Foo();
  22. console.log( o._num );  //undefined
  23. console.log(o.set_num(11)); //undefined
  24. console.log(o._num); //undefined 取不出数据

闭包的应用:实现私有数据和缓存数据

闭包案例之斐波那契数列

没使用闭包的函数式

  1. var count = 0;
  2. var fib = function (n){
  3. count++;
  4. if(n< 0)throw new Error('不允许出现负数');
  5. if(n === 0||n === 1)return 1;
  6. // return fib(n-1)+fib(n-2);
  7. return arguments.callee(n-1) + arguments.callee(n-2);
  8. }
  9.  
  10. console.log(fib(16));
  11. console.log(count);
  12. //分别计算第1、2、4、8、16、32项对应的次数为1、3、9、67、3193、7049155

从以上计算的次数可以看出性能的损耗很严重,那么闭包可以在此解决的问题是已经运算过得数据缓存下来

  1. var count = 0;
  2. var fib = (function(){
  3. var arr = [];
  4. return function (n){
  5. count++;
  6. if(n < 0)throw new Error('不允许出现负数');
  7. var res = arr[n];//缓存数据 判断有无数据
  8. if(res !== undefined){
  9. return res;
  10. }
  11. else {
  12. if(n === 0||n ===1) {
  13. res = 1;
  14. }
  15. else{
  16. res = fib(n - 1)+fib(n - 2);
  17. }
  18. }
  19. arr[n] = res;
  20. return res;
  21. }
  22. })();
  23. console.log(fib(100));
  24. console.log(count);//199

第二种写法

  1. var count = 0;
  2. var fib = (function(){
  3. var arr = [];
  4. return function(n){
  5. count++;
  6. return feibo(arr,n);
  7. }
  8. })();
  9. function feibo(arr,n){
  10. if(n < 0)throw new Error("不允许出现负数");
  11. var res = arr[n];
  12. if(res != undefined){
  13. return res;
  14. }else{
  15. if(n === 0 ||n === 1){
  16. res = 1;
  17. }else{
  18. res = fib(n - 1) + fib(n - 2);
  19. }
  20. }
  21. arr[n] = res;
  22. return res;
  23. }
  24. console.log(fib(100));
  25. console.log(count);

从上式可以看出闭包带来的好处;

拓展:谈到数据缓存也可以不用闭包,下面函数则与闭包无关

  1. var fib = function ( n ) {
  2. var res = fib[ n ]; // 先到函数名中取
  3. if ( res !== undefined ) {
  4. return res;
  5. } else {
  6. // 如果是 1 或 0 则将 1 返回给 res
  7. // 否则递归结果交给 res;
  8.  
  9. if ( n === 0 || n === 1 ) {
  10. res = 1;
  11. } else {
  12. res = arguments.callee( n - 1 ) +
  13. arguments.callee( n - 2 );
  14. }
  15.  
  16. fib[ n ] = res;
  17. // 将计算的结果放到数组中, 那么下一次再计算的
  18. // 时候可以直接拿来用, 就不用重新计算
  19. fib.len++;//每次赋值完后
  20. return res;
  21. }
  22. };
  23. fib.len = 0;//给函数添加一个属性
  24. console.log(fib(100));
  25. console.log(fib.len)//101

javascript面向对象之闭包的更多相关文章

  1. 关于javascript面向对象之闭包

    要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量,而在函数外部无法 ...

  2. JavaScript面向对象,闭包内存图,闭包和作用域

    var i = 10; function test(){ var j; i=20; //未定义 function test(){ j='hello'; } console.log(test()); / ...

  3. JavaScript面向对象之闭包的理解

    首先了解一下什么是闭包,闭包是一个函数,通常被称为闭包函数或者绑定函数,该函数运行在一个特殊的环境里,该环境定义了一些本地变量,当该函数被调用时,仍可以使用这些本地变量. 当一个函数在不位于它所处的环 ...

  4. JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式

      前  言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...

  5. JavaScript函数、闭包、原型、面向对象

    JavaScript函数.闭包.原型.面向对象 断言 单元测试框架的核心是断言方法,通常叫assert(). 该方法通常接收一个值--需要断言的值,以及一个表示该断言目的的描述. 如果该值执行的结果为 ...

  6. javascript(面向对象,作用域,闭包,设计模式等)

    javascript(面向对象,作用域,闭包,设计模式等) 1. 常用js类定义的方法有哪些? 参考答案:主要有构造函数原型和对象创建两种方法.原型法是通用老方法,对象创建是ES5推荐使用的方法.目前 ...

  7. 闭包初体验 -《JavaScript面向对象编程指南》

    下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 参考<JavaScript面向对象编程指南> 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函 ...

  8. JavaScript学习笔记(三)——this、原型、javascript面向对象

    一.this 在JavaScript中this表示:谁调用它,this就是谁. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是一个动态的对象,根据调用的对象不同而发生变化, ...

  9. JavaScript学习总结(三)——this、原型、javascript面向对象

    一.this 在JavaScript中this表示:谁调用它,this就是谁. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是一个动态的对象,根据调用的对象不同而发生变化, ...

随机推荐

  1. IT行业,需要经常锻炼,开篇从本钱开始

    今天下完班,和部门兄弟一起去打了两小时乒乓球,大汗淋漓,很痛快. 败给了两个高手,感觉年龄大了些,灵活性没有以前那么好了. 想想以前读书时,在整个学校都叱诧风云,如今即败给了几个老手,唉. 看来以后要 ...

  2. NET Platform Standard

    NET Platform Standard 相关博文:ASP.NET 5 Target framework dnx451 and dnxcore50 .NET Platform Standard:ht ...

  3. mysql READ-COMMITTED 模式下 行锁不会升级到表级锁

    mysql> select sn,id,info from s100 group by id; +-----+------+------+ | sn | id | info | +-----+- ...

  4. HDU 4981 Goffi and Median(水)

    HDU 4981 Goffi and Median 思路:排序就能够得到中间数.然后总和和中间数*n比較一下就可以 代码: #include <cstdio> #include <c ...

  5. Linux目录结构和常用命令

    源地址:http://www.cnblogs.com/JCSU/articles/2770249.html 一.Linux目录结构 你想知道为什么某些程序位于/bin下,或者/sbin,或者/usr/ ...

  6. jquery中怎么删除<ul>中的整个<li>包括节点

    .$('ul li').remove(); .$('ul li').each(function(){ $(this).remove(); }); .$("ul").find(&qu ...

  7. html5实现拖拽文件上传

    以下是自学it网--中级班上课笔记 网址:www.zixue.it html文件 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict ...

  8. 改动Oracle GoldenGate(ogg)各个进程的读检查点和写检查点

    请注意:请谨慎改动Oracle GoldenGate(ogg)各个进程的读检查点和写检查点. 请确保已经 掌握 ogg 各个进程的读检查点和写检查点的详细含义. BEGIN {NOW | yyyy-m ...

  9. poj3461 Oulipo (KMP模板题~) 前面哪些也是模板题 O.O

    # include <stdio.h> # include <algorithm> # include <string.h> using namespace std ...

  10. 关于PHP的内置服务器的使用

    今天刚开始正式学习PHP(之前有一点了解),推荐学习的网站是w3school.一开始不知道tomcat服务器不支持PHP脚本,直接把.php文件放到tomcat里面去运行,结果嵌入的php代码段没有什 ...