八 闭包
MDN闭包
定义:当函数在它定义作用域外面执行的时候还能记住它的作用域
1.当你调用当前函数的时候 定义它的作用域销毁了
2 在使用这个函数的时候,使用了作用域链里的变量
简单的说,就是函数执行后产生的作用域本该被销毁,但是却在函数外部以变量的形式被保存了,就形成了闭包。
相当于引用了这部分内容所在的堆地址,所以不会被垃圾回收机制回收,内存得不到释放,所以容易产生内部泄漏。
但是现在电脑内存比较大,所以还不太容易泄漏。
应用场景: setTimeout
基础数据类型放在栈地址
引用数据类型放在堆地址
词法作用域 vs 动态作用域
js是词法作用域: 定义的时候已经创建了作用域
动态作用域是在执行时才会创建作用域
执行上下文栈
全局代码
函数代码
eval代码
变量对象
存储在当前上下文中的变量和函数对象
入栈时找定义的变量和函数表达式存储在AO中 预编译四部曲
闭包的危害
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露(占用的内存多了,剩的内存少了,像是泄露)。
解决for循环
解决for循环直接输出10的问题 用ES6的let 或者 立即执行函数
function test ( ) {
var arr = [ ];
for( var i = 0 ; i < 10; i++){
/* arr [ i ] = function ( ) {
console.log( i );
}*/
//改为立即执行函数,就可以打印出0~9而不是10个10
(function ( j ) {
arr [ j ] = function ( ) {
console.log( j );
}
} ( i ) );
}
return arr;
}
var myArr = test ( ) ;
for ( var j = 0; j < 10; j++ ) {
myArr [ j ] ( );
}
闭包的应用
模块化开发
好处:防止污染全局变量
实现累加器,实现函数公有
eg1:
function add ( ) {
var num = 100;
function demo ( ) {
num++;
console.log ( num ) ;
}
return demo;
}
var counter = add ( ) ;
counter ( ) ; //101
counter ( ) ; //102
counter ( ) ; //103
因为 b 被保存到了函数外部,所以在a执行完并销毁自身作用域时, b 的作用域仍然指向a的AO , 所以是a函数的AO中的num一直在增加。
eg2 :
function test ( ) {
var num = 100;
function a ( ) {
num ++ ;
console.log ( num ) ;
}
function b ( ) {
num -- ;
console.log ( num ) ;
}
return [a , b ] ;
}
var myArr = test ( ) ;
myArr [ 0 ] ( ) ; // 101
myArr [ 1 ] ( ) ; // 100
2.可以做缓存( 存储结构 )
3.可以实现封装,属性私有化。
4.模块化开发,防止污染全局变量。