闭包
概念
当在函数内定义函数时,将内部函数作为返回值称该内部函数为闭包。闭包可以使用外部函数的变量,这样一来,当外部函数执行完毕后,相关变量并不会被销毁,可以被返回出来的内部函数调用。
function outerFun() {
let n = 10;
function innerFun() { //内部函数
console.log(n); //使用了外部函数outerFun的变量
}
return innerFun; //作为闭包被返回
}
const fun1 = outerFun(); //拿到闭包
fun1(); //使用未能被销毁的变量n
fun1(); //可反复使用
console.log(n); //报错,n只能通过闭包函数来访问
在ES6之前,可用闭包来实现代码封装和模块化。
因为闭包操作的内部变量被视作局部变量,不会污染全局,从而实现不同模块间的变量隔离。
闭包实现代码封装和模块化
//文件1的代码:
var modileFun1 = (function(){ //通过立即执行函数定义一个模块
var a = 1, b = 2;
function add(){
console.log(a+b);
}
return add;
})();
//文件2的代码:
modileFun1(); //()()该立即执行函数内的函数返回add函数作为闭包赋值给modileFun1,
//然后调用modileFun1可以执行add,同时保留了add执行时的上下文空间
更直接的闭包代码块封装
//文件1的代码:
var modileFun1 = (function(){ //通过立即执行函数定义一个模块
var a = 1, b = 2;
return function (){
console.log(a+b);
};
})();
//文件2的代码:
modileFun1();
闭包的好处与坏处
好处:
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
坏处:
①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响;
立即执行函数
函数声明和函数表达式
函数的定义可以通过函数声明来实现,eg:function fun1( ){..}
也可以通过函数表达式来实现,eg:var fun1 = function( ){...},本例是将函数表达式定义的匿名函数赋给了一个变量
function( ){...}称为匿名函数,属于函数表达式
函数声明和函数表达式的区别
1.JS的引擎在解析JS代码时会对函数声明进行函数声明提升,而函数表达式只有执行到它时才会解析。
2.函数表达式后面加括号可以立即执行,称为立即执行函数,函数声明只能显式调用。
立即执行函数概念
使用函数表达式定义一个匿名函数,然后再在匿名函数后面加()就可以立即执行
写法:
(function(){ //用括号把匿名函数括起来,后加()调立即执行
//do something
}) ()
(function(){ //用括号把整个立即执行函数括起来
//do someting
} ())
void function(){
//do something
} ()
new function(){ // +,-,~,! function(){}() 也可以
//do something
} ()
立即执行函数的作用
1.可以用于变量隔离,立即执行函数内部定义的变量不会污染全局变量,即使命名相同
2.可以封装变量,立即执行函数内部的变量无法从外部读取,可以被封装成该代码段的私有变量
补充:立即执行函数封装的变量只在该代码段内可以访问,而更进一步通过闭包封装的变量可以在任意位置通过执行闭包函数来访问。