Javascript闭包总结

什么是闭包

闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。闭包的特点:

  1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态
  2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区

简单的说,Javascript允许使用内部函数—即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

闭包的几种写法和用法

首先要明白,在JS中一切都是对象,函数是对象的一种。下面先来看一下闭包的5种写法,简单理解一下什么是闭包

第一种写法

function Circle(r){
    this.r = r;
}
Circle.PI = 3.1415926;
Circle.prototype.area = function(){
    return Circle.PI  this.r  this.r;
}
var c = new Circle(1.0);
console.log(c.area());

这种写法没什么特别的,只是给函数添加一些属性

第二种写法

var Circle = function() {
   var obj = new Object();
   obj.PI = 3.14159;
   obj.area = function( r ) {
       return this.PI  r  r;
   }
   return obj;
}
var c = new Circle();
console.log( c.area( 1.0 ) );

这种写法是声明一个变量,将一个函数当作值赋给变量

第三种写法

var Circle = new Object();
Circle.PI = 3.14159;
Circle.Area = function( r ) {
    return this.PI  r  r;
}
console.log( Circle.Area( 1.0 ) );

这种方法最好理解,就是new 一个对象,然后给对象添加属性和方法

第四种写法

var Circle={
    "PI":3.14159,
    "area":function(r){
        return this.PI  r  r;
    }
};
console.log( Circle.area(1.0) );

这种方法使用较多,也最为方便。var obj = {}就是声明一个空的对象

第五种写法

var Circle = new Function("
    this.PI = 3.14159;
    this.area = function( r ) {
        return rrthis.PI;
    }
");
alert( (new Circle()).area(1.0) );

总的来说,上面几种方法,第2中和第4中较为常见,大家可以根据习惯选择

上面代码中出现了JS中常用的Prototype,那么Prototype有什么用呢?下面我们来看一下:

var dom = function(){};
dom.Show = function(){
    alert("Show Message");
};
dom.prototype.Display = function(){
    alert("Property Message");
};
dom.Display(); //error
dom.Show();
var d = new dom();
d.Display();
d.Show(); //error

我们首先声明一个变量,将一个函数赋给他,因为在Javascript中每个函数都有一个Portotype属性,而对象没有。添加两个方法,分别直接添加和添加Prototype上面,来看下调用情况。分析结果如下:

1、不使用prototype属性定义的对象方法,是静态方法,只能直接用类名进行调用!另外,此静态方法中无法使用this变量来调用对象其他的属性

2、使用prototype属性定义的对象方法,是非静态方法,只有在实例化后才能使用!其方法内部可以this来引用对象自身中的其他属性!

下面我们再来看一段代码:

var dom = function(){
    var Name = "Default";
    this.Sex = "Boy";
    this.success = function(){
        alert("Success");
    };
};
console.log(dom.Name);
console.log(dom.Sex);

大家先看看,会显示什么呢? 答案是两个都显示Undefined,为什么呢?这是由于在Javascript中每个function都会形成一个作用域,而这些变量声明在函数中,所以就处于这个函数的作用域中,外部是无法访问的。要想访问变量,就必须new一个实例出来

var html = {
    Name:'Object',
    Success:function(){
        this.Say = function(){
            alert("Hello,world");
        };
        alert("Obj Success");
    }
};

再来看看这种写法,其实这是Javascript的一个”语法糖”,这种写法相当于:

var html = new Object();
    html.Name = 'Object';
    html.Success = function(){
            this.Say = function(){
                    alert("Hello,world");
            };
            alert("Obj Success");
    }

变量html是一个对象,不是函数,所以没有Prototype属性,其方法也都是公有方法,html不能被实例化。否则会出现错误。但是他可以作为值赋给其它变量,如var o = html;我们可以这样使用它:

alert(html.Name);
html.Success();

细心的人会问,怎么访问Success方法中的Say方法呢?上面刚说过由于作用域的限制,是访问不到的。所以要用下面的方法访问:

var s = new html.Success();
s.Say();

html.Success.prototype.Show = function(){   //还可以写到外面
    alert("HaHa");
};
var s = new html.Success();
s.Show();

闭包的用途

事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率

匿名自执行函数

我们知道所有的变量,如果不加上var,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,比如UI的初始化,那么我们可以使用闭包:

var data= {
    table : [],
    tree : {}
};
(function(dm){
    for(var i = 0; i < dm.table.rows; i++){
       var row = dm.table.rows[i];
       for(var j = 0; j < row.cells; i++){
           drawCell(i, j);
       }
    }
})(data);

我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象

结果缓存

我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留

var CachedSearchBox = (function(){
    var cache = {},
       count = [];
    return {
       attachSearchBox : function(dsid){
           if(dsid in cache){   //如果结果在缓存中
              return cache[dsid];   //直接返回缓存中的对象
           }
           var fsb = new uikit.webctrl.SearchBox(dsid);   //新建
           cache[dsid] = fsb;   //更新缓存
           if(count.length > 100){   //保正缓存的大小<=100
              delete cache[count.shift()];
           }
           return fsb;
       },
       clearSearchBox : function(dsid){
           if(dsid in cache){
              cache[dsid].clearSelection();
           }
       }
    };
})();
CachedSearchBox.attachSearchBox("input");

这样我们在第二次调用的时候,就会从缓存中读取到该对象

封装

var person = function(){
    var name = "default";    //变量作用域为函数内部,外部无法访问
    return {
       getName : function(){
           return name;
       },
       setName : function(newName){
           name = newName;
       }
    }
}();
print(person.name);   //直接访问,结果为undefined
print(person.getName());
person.setName("abruzzi");
print(person.getName());    

得到结果如下:  

undefined
default
abruzzi

实现类和继承

function Person(){
    var name = "default";
    return {
       getName : function(){
           return name;
       },
       setName : function(newName){
           name = newName;
       }
    }
};
var p = new Person();
p.setName("Tom");
alert(p.getName());
var Jack = function(){};
Jack.prototype = new Person();   //继承自Person
Jack.prototype.Say = function(){   //添加私有方法
    alert("Hello,my name is Jack");
};
var j = new Jack();
    j.setName("Jack");
    j.Say();
alert(j.getName());

我们定义了Person,它就像一个类,我们new一个Person对象,访问它的方法。下面我们定义了Jack,继承Person,并添加自己的方法

时间: 2024-09-03 03:44:58

Javascript闭包总结的相关文章

javascript闭包

前言 闭包对于初学者而言一直是一个不太好理解的概念.最近在学习javascript的时候碰巧看到了关于这方面的讲解,自己才明白了许多,所以把它写出来分享给大家.当然,本文也是参考了很多blog和书籍,加上自己的理解写出来的,文章末尾会附上对应的参考文档. 基础知识  变量作用域 //javascript的变量作用域可以分为两种:全局变量和局部变量. //在函数内声明的变量就是局部变量,这个变量在函数体内可访问,在函数外部无法直接读取局部变量. //例如: var globalVariable =

javascript闭包的高级使用方法实例

这篇文章介绍了javascript闭包的高级使用方法实例,有需要的朋友可以参考一下   扩展 Code: 复制代码 代码如下: var blogModule = (function (my) {  my.AddPhoto = function () { //添加内部代码  };  return my; }(blogModule)); Say: 将自身传进方法,然后实现了方法的扩展,有点象零件组装啊 Code: 复制代码 代码如下: var blogModule = (function (my)

基于javascript 闭包基础分享

如果对作用域,函数为独立的对象这样的基本概念理解较好的话,理解闭包的概念并在实际的编程实践中应用则颇有水到渠成之感. 在DOM的事件处理方面,大多数程序员甚至自己已经在使用闭包了而不自知,在这种情况下,对于浏览器中内嵌的JavaScript引擎的bug可能造成内存泄漏这一问题姑且不论,就是程序员自己调试也常常会一头雾水. 用 简单的语句来描述JavaScript中的闭包的概念:由于JavaScript中,函数是对象,对象是属性的集合,而属性的值又可以是对象,则在函数内 定义函数成为理所当然,如果

javascript闭包的理解

 1.首先我们要知道变量作用域链 变量的作用域分两种:全局变量和局部变量.没有定义到任何函数中的变量为全局变量,在函数中定义的变量为局部变量,注意在函数内部定义变量时一定要使用var关键字,不带var关键字的变量为全局变量. javascript中每一段代码都有与之关联的作用域链,这个作用域链是一个对象列表或者链表,定义了这段代码"作用域"中的变量.顶层代码的作用域由全局变量组成:不包含嵌套的函数的作用域链有两个对象:一个是定义的函数参数和局部变量的对象,一个是全局变量对象:而嵌套函数

javascript 闭包详解

 这篇文章主要详细介绍了javascript 闭包的相关资料,十分详尽,需要的朋友可以参考下     javascript 闭包是一个很有趣的东东.看了些相关资料http://www.jb51.net/article/29472.htm,对其印象最深刻的是:实现了public 和private. 创建一个非匿名闭包最简单的语法是:   代码如下: var obj = (function(){//各种代码 });   闭包最经典的例子:   代码如下: var makeCounter = (fun

关于javascript闭包的一点疑问

问题描述 关于javascript闭包的一点疑问 闭包存储局部变量的机理是什么?它如何存储的?比如如下一个闭包 function test(){ var num = 10; return function(){ num++; return num; }; }; var n = test(); alert(n()); //返回11 alert(n()); //返回12,实现了累加 alert(n()); //继续累加 第二次alert(n())通过闭包实现了累加,但是这个局部变量num是如何存储在

函数-关于javascript闭包的一点疑问

问题描述 关于javascript闭包的一点疑问 function create(){ var arr = new Array(); for (var i=0; i<10; i++){ arr[i] = function(num){ return function(){ return num; }; }(i);// (i)有是什么意思?} 解决方案 匿名函数的参数,可以这么理解 var f = function(num){ return function(){ return num; };};a

JavaScript 闭包环境很奇特 - 相当于类与实例的关系?!

JavaScript 闭包环境很奇特 - 相当于类与实例的关系?! 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 又一个疑问贴! 不过我相信,问题并不是难在如何解决,最终就是个能解决与不能解决

Javascript闭包简单理解

原文:Javascript闭包简单理解 提到闭包,想必大家都早有耳闻,下面说下我的简单理解.说实话平时工作中实际手动写闭包的场景并不多,但是项目中用到的第三方框架和组件或多或少用到了闭包.所以,了解闭包是非常必要的.呵呵... 一.什么是闭包简而言之,就是能够读取其他函数内部变量的函数.由于JS变量作用域的特性,外部不能访问内部变量,内部可以外部变量. 二.使用场景1. 实现私有成员.2. 保护命名空间,避免污染全局变量.3. 缓存变量. 先看一个封装的例子: var person = func

Javascript闭包的一些研究

原文:Javascript闭包的一些研究     本文不谈闭包的概念,因为概念容易把人搞晕,本文希望通过几个鲜活的例子来探究闭包的性质,相信对理解闭包会有所帮助.   程序1 var f = (function() { var n = 10; return function() { ++n; console.log(n); } })(); f(); 输出: 11 结论: 闭包函数可以访问外层函数中的变量.   程序2 var arr = []; (function() { var n = 0;