1 .定义在函数内部的函数,能够读取其他函数内部变量的函数。将变量包工在匿名函数中,突破函数作用域的限制。
2 .闭包是一种特殊的对象。它有两部分组成,函数,以及创建这个函数的环境。环境是由闭包创建是在作用域内的任何变量组成
3.闭包的用途:
1.读取函数内部的变量,创建含有隐藏数据的函数。
2.让变量的值始终保存在内存中。f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2也是依赖于f1,所以f1始终在内存中,不会再函数调用之后,被垃圾回收机制回收。用闭包模拟私有方法,不仅可以有利于限制对代码的访问,还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分。
var Counter=(function(){
var private=0;
function changeBy(val){
private+=val
}
// 共享函数和变量。
// 该共享环境创建于一个匿名的函数体内,该函数一经定义就立刻执行。环境中有两个私有项:一个变量,和一个私有函数,这些东西都是无法在匿名函数外部直接访问到。他的访问必须通过匿名包装器返回的三个公共函数访问
return {
// 私有函数
choose1:function(){
changeBy(1);
},
choose_1:function(){
changeBy(-1);
},
value:function(){
return private;
}
}
})()
var db = (function() {
// 创建一个隐藏的object, 这个object持有一些数据
// 从外部是不能访问这个object的
var data = {};
// 创建一个函数, 这个函数提供一些访问data的数据的方法
return function(key, val) {
if (val === undefined) { return data[key] } // get
else { return data[key] = val } // set
}
// 我们可以调用这个匿名方法
// 返回这个内部函数,它是一个闭包
})();
db('x'); // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x'); // 返回 1
// 我们不可能访问data这个object本身
// 但是我们可以设置它的成员
3.由于有了闭包,而且函数也是对象,一个函数可以向一个传统对象那样拥有自己的属性,私有数据和状态,不会随着栈而清空,许多简单的功能也无需借助object来实现了。
4.闭包是一种设计原则,他通过分析上下文,来简化用户的调用,让用户在不知晓的情况下达到他的目的。封装变量,computed计算属性,将之前的计算属性缓存起来,下次调的时候就可以直接返回结果,而不需要参与运算,这里存放结果的变量不需要暴露给外界,并且需要在函数运行之后,任然保存,所以可以采用闭包,源码采用的是消息发布订阅模式
5.管理私有变量和私有方法,将变量的变化封装在安全的环境中
4 .闭包注意的问题
1.闭包会使函数中的变量都保存在内存中,内存的消耗很大,所有在退出函数的时候,不用的变量都要消除
2.闭包会在父函数外部,改变父函数内部变量的值。所以如果你把父函数当成对象使用,把闭包当成他的公用方法,把内部变量当做他的私有属性,这时一定要小心,不要随便改变父函数内部变量的值。
3.自执行函数不是闭包,但是他解决全局变量的污染问题。
5 .不使用return关键字的闭包实例 setTimeout函数
for(var i = 0, len = btns.length; i < len; i++) {//还有这一种,好像异步执行的都可以?
(function(i) {
btns[i].onclick = function() {
alert(i);
}
}(i))
}
6 .闭包的经典使用场景:通过循环给页面上多个dom绑定事件
7 .封装变量
8 .延长局部变量的使用寿命
var report = (function() {
var imgs = [];
return function(src) {
var img = new Image();
imgs.push(img);
img.src = src;
}
}())
9 .模拟实现对象的写法
10 .为某一个函数执行前先执行的函数提供参数。
11 .将函数关联到对象的实例方法--封闭一个js对象来参与一个特定的dom元素的交互,并且想在dom元素上对应的事件被触发的时候执行这些方法。
12 .如果一个函数依赖另外一个或几个函数,但是其他函数并不期望与任何其他的代码产生交互,那么就可以使用闭包来扩展组织这些函数。