【JS】闭包

One Day One Tip 之 闭包

时间:2016-08-30 13:39:33
作者:zhongxia

总结:

概念:
闭包:能够读取其他函数内部变量的函数,在JavaScript中,一个函数return它内部的一个函数。

原理:通过引用变量从而阻止该变量被垃圾回收的机制

优:

  1. 封装私有属性和私有方法,加强封装性,可以达到对变量的保护作用。
  2. 更好的组织代码,比如模块化

缺:

  1. 增加了内存的消耗,并且在某些浏览器下,由于垃圾回收机制不同,有可能导致内存溢出
  2. 增加复杂度
  3. 由于闭包内部变量优先级高于外部变量,所以多查找作用域链中的一个层次,就会在一定程度上影响查找速度。

零、所需知识

要理解闭包,首先必须理解 JavaScript 特殊的变量作用域。
变量的作用域无非就是两种: 全局变量局部变量

JavaScript语言的特殊之处,就在于 函数内部可以直接读取全局变量。
不使用 var 声明的变量,则为全局变量。 b = 100;

function fn(){
  var a = b = 1;  
  // ==> var a = window.b = 1;  // a 是局部变量   b 是全局变量
}
fn();
console.log("b = ",b); // 1
console.log("a = ",a); //VM783:1 Uncaught ReferenceError: a is not defined

函数外部无法访问局部变量。 因此在外部,访问 a 变量 报错。 而 b 变量是 全局变量,因此可以访问到。

一、闭包是什么

闭包是概念?
闭包是指某种程序语言中的代码块允许一级函数存在并且在一级函数中所定义的自由变量能不被释放,直到一级函数被释放前,一级函数外也能应用这些未释放的自由变量。

我的理解就是:闭包就是能够读取其他函数内部变量的函数
由于在JavaScript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单的理解成 『定义在一个函数内部的函数
本质上: 闭包就是将函数内部和外部链接起来的一座桥梁

//eg: example
function a(x){
  var tmp = 10;
  return function(y){
     return (x+y)+(++tmp);
  }
}
var b = a(10);
b(5);  //26, 每执行一次 tmp 加 1

因为 a() 执行后,返回 的 方法 b, 内部引用了 tmp 变量, 导致 tmp 变量的标记+1, 垃圾回收机制就不会清除 tmp这个变量。
然后外部就可以继续访问到 tmp 变量。

二、闭包的作用

  1. 读取函数内部的变量
  2. 让内部的变量始终保持在内存中
  3. 设计私有方法和变量【封装框架的时候更明显,典型的如Jquery】
var jQuery = (function(){  
  
    var jQuery = function(){  
    //TODO  
    }  
    return (window.$ = window.jQuery = jQuery);       
});  

三、闭包的优缺点

优点

  1. 延长作用域链。
  2. 更好的组织代码,比如模块化,异步代码转同步等。
  3. 加强封装性,可以打到对变量的保护(第二点的加强)
  4. 处理异步造成的变量不能即时传递的问题

缺点

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除
  2. 增加内存的消耗
  3. IE浏览器上 因为回收机制,有内存溢出的风险
  4. 增加了代码复杂度

四、闭包用法实战

1. 对fun的计算方式进行定制

实际使用的时候,闭包可以创建出非常优雅的设计,允许对funarg上定义的多种计算方式进行定制。如下就是数组排序的例子,它接受一个排序条件函数作为参数:

[1, 2, 3].sort(function (a, b) {
  ... // 排序条件
});

同样的例子还有,数组的map方法是根据函数中定义的条件将原数组映射到一个新的数组中:

[1, 2, 3].map(function (element) {
  return element * 2;
}); // [2, 4, 6]

2. 函数式参数

使用函数式参数,可以很方便的实现一个搜索方法,并且可以支持无限制的搜索条件:

someCollection.find(function (element) {
  return element.someProperty == 'searchCondition';
});

还有应用函数,比如常见的forEach方法,将函数应用到每个数组元素:

[1, 2, 3].forEach(function (element) {
  if (element % 2 != 0) {
    alert(element);
  }
}); // 1, 3

顺便提下,函数对象的 apply 和 call方法,在函数式编程中也可以用作应用函数。 apply和call已经在讨论“this”的时候介绍过了;这里,我们将它们看作是应用函数 —— 应用到参数中的函数(在apply中是参数列表,在call中是独立的参数):

(function () {
  alert([].join.call(arguments, ';')); // 1;2;3
}).apply(this, [1, 2, 3]);

3. 延迟调用

闭包还有另外一个非常重要的应用 —— 延迟调用:

var a = 10;
setTimeout(function () {
  alert(a); // 10, after one second
}, 1000);

4. 回调函数

//...
var x = 10;
// only for example
xmlHttpRequestObject.onreadystatechange = function () {
  // 当数据就绪的时候,才会调用;
  // 这里,不论是在哪个上下文中创建
  // 此时变量“x”的值已经存在了
  alert(x); // 10
};
//...

5. 创建封装的作用域来隐藏辅助对象:

var foo = {};

// 初始化
(function (object) {

  var x = 10;

  object.getX = function _getX() {
    return x;
  };

})(foo);

alert(foo.getX()); // 获得闭包 "x" – 10

参考文章

  1. 阮一峰-学习Javascript闭包(Closure)
  2. 浅析jQuery核心架构中应用Closure(闭包)的设计模式
  3. 用一道面试题考察对闭包的理解
  4. 深入理解JavaScript系列(16):闭包(Closures)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容