首先,先来讲一下闭包的定义。什么是闭包,闭包就是有权访问另外一个函数做用域内变量的函数,如例:闭包
function abc(){ 函数
//这里是abc()做用域
let a = 1;
function add(){性能
//这里是add()做用域
a++;
console.log(a);//在这里能够访问到a变量
};
add();
add();
add();
}spa
console.log(a) //在这里会直接报错,没法访问abc函数中的a变量
abc();//输出2,3,4对象
要知道,js的每一个函数都是一个个独立的密闭空间,它能够获取外界信息,可是外界却没法直接看到里面的内容。将变量 a 放进小黑屋里,只有add 函数能接触到变量 a,并且在函数 abc 外定义同名的变量 a也是互不影响的,这就是所谓的加强“封装性”。事件
看到了吗,这就是闭包,如此简单。内存
好,接下来,咱们来看看她是怎么执行的作用域
function abc(){io
//这里是abc()做用域
let a = 1;
function add(){console
//这里是add()做用域
a++;
console.log(a);//在这里能够访问到a变量
};
return add;
}
var c = abc();//这是函数表达式
c();//打印2
那咱们能够看到,这里的c()就至关因而abc();,好,那有人会问我不是在var c = abc();的时候就已经把abc函数赋值给c了吗,难道c不等于abc()?,为何下面一行我不能够直接调用c,还要给他加括号呢?
是这样的,在把abc函数赋值给c的时候,我真正赋值给他的是什么?在abc函数中,你们能够看一下,我返回了什么,我返回的是add,也就是说var c = abc();这一行至关因而var c = add;在这一步个人操做的是什
么,是否是进行了一次赋值,而我拿到的是一个标识符,一个函数名称,它并无实际意义,在下一行在给了它()以后,它才具有了调用这个函数的资格。再看第二个例子:
function abc(){
//这里是abc()做用域
let a = 1;
function add(){
//这里是add()做用域
a++;
console.log(a);//在这里能够访问到a变量
};
return add();//你们看下这里返回的是什么
}
A实例:
var c = abc();//这是函数表达式
c;//打印2
或者能够这么写:
B实例:
var c = abc;//这是函数表达式
c();//打印2
你们能够看一下这两个例子,不一样的地方在于返回的值,和赋给变量的值,在第二个例子中,我返回的是add(),因此,变量c就是add();在A实例中我赋给c的函数名称和函数体,在下一行,我就直接调用c就可
以了,但在B实例中,我赋给c的是函数名称,而没有函数体,在下一行,我就必须加上,同时调用他,才能获得返回值。
结论:在函数中真正重要的角色是什么,是函数体,也就是这个();
闭包的优势:
1.使用闭包代替全局变量
2.函数外或在其余函数中访问某一函数内部的参数
3.在函数执行以前为要执行的函数提供具体参数
4.在函数执行以前为函数提供只有在函数执行或引用时才能知道的具体参数
5.为节点循环绑定click事件,在事件函数中使用当次循环的值或节点,而不是最后一次循环的值或节点
6.暂停执行
7.包装相关功能
闭包的缺点:
1.内存消耗
一般来讲,函数的活动对象会随着执行期上下文一块儿销毁,可是,因为闭包引用另一个函数的活动对象,所以这个活动对象没法被销毁,这意味着,闭包比通常的函数须要更多的内存消耗。解决方法是,在退出函数以前,将不使用的局部变量所有删除。
2.性能问题
使用闭包时,会涉及到跨做用域访问,每次访问都会致使性能损失。所以在脚本中,最好当心使用闭包,它同时会涉及到内存和速度问题。不过咱们能够经过把跨做用域变量存储在局部变量中,而后直接访问局部变量,来减轻对执行速度的影响。