闭包
闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量参考链接 前文了解了,预编译的过程,了解了作用域和作用域链。都为闭包准备的基础 当内部函数被返回到外部并保存时一定会产生闭包,闭包会产生原来的作用域链不释放,过渡的闭包可能会导致内存的泄露,或加载过慢。 通过作用域链的图解分析来说明不释放问题
function test1 ( ) {
function test2 ( ) {
var b = 2 ;
console. log ( a) ;
}
var a = 1 ;
return test2 ( )
}
var c = 3 ;
var test3 = test1 ( ) ;
test3 ( ) ;
函数test1 “” [[scope]] Scope Chain 作用域链
Scope Chain
GO 全局执行上下文
GO全局执行上下文 “” this window window object document object test1 function c 3 test3 function
函数test1 “” [[scope]] Scope Chain 作用域链
test1 Scope Chain
Scope Chain作用域链 “” 0 test1的AO 1 GO
test1的AO
函数test1的AO函数执行期上下文 “” this window arguments [] test2 function a 1
test2被定义
函数test2 “” [[scope]] Scope Chain 作用域链
test2 Scope Chain
Scope Chain作用域链 “” 0 test1的AO 1 GO
GO 全局执行上下文
GO全局执行上下文 “” this window window object document object test1 function c 3 test3 function
函数test1 “” [[scope]] Scope Chain 作用域链
test1 Scope Chain
Scope Chain作用域链 “” 0 test1的AO 这个关联被销毁 1 GO
test1的AO
函数test1的AO函数执行期上下文 “” this window arguments [] test2 function a 1
test2被定义
函数test2 “” [[scope]] Scope Chain 作用域链
test2 Scope Chain
Scope Chain作用域链 “” 0 test1的AO 1 GO
GO 全局执行上下文
GO全局执行上下文 “” this window window object document object test1 function c 3 test3 function
函数test1 “” [[scope]] Scope Chain 作用域链
test1 Scope Chain
Scope Chain作用域链 “” 0 test1的AO 这个关联被销毁 1 GO
test1的AO
函数test1的AO函数执行期上下文 “” this window arguments [] test2 function a 1
test2执行
函数test2 “” [[scope]] Scope Chain 作用域链
test2 Scope Chain
Scope Chain作用域链 “” 0 test2的AO 1 test1的AO 2 GO
test2的AO
Scope Chain作用域链 “” this window arguments [] b 2
GO 全局执行上下文
GO全局执行上下文 “” this window window object document object test1 function c 3 test3 function(test2)
函数test1 “” [[scope]] Scope Chain 作用域链
test1 Scope Chain
Scope Chain作用域链 “” 0 test1的AO 这个关联被销毁 1 GO
test1的AO
函数test1的AO函数执行期上下文 “” this window arguments [] test2 function a 1
test3执行结束
函数test2 “” [[scope]] Scope Chain 作用域链
test2 Scope Chain
Scope Chain作用域链 “” 0 test2的AO 这个AO被销毁 1 test1的AO test1的仍然存在 2 GO
test2的AO
Scope Chain作用域链 “” this window arguments [] b 2
GO 全局执行上下文
GO全局执行上下文 “” this window window object document object test1 function c 3 test3 function(test2)
闭包的用例
function test ( num) {
var bNum = arguments[ 0 ] || 10 ;
function supply ( ) {
bNum + = 10 ;
console. log ( bNum)
}
function sale ( ) {
bNum-- ;
console. log ( bNum) ;
}
return [ supply, sale]
}
var bArray = test ( )
bArray[ 0 ] ( )
bArray[ 1 ] ( )
function test ( num) {
var bNum = arguments[ 0 ] || 10 ;
var obj = {
supply: function ( ) {
bNum + = 10 ;
console. log ( bNum)
} ,
sale: function ( ) {
bNum-- ;
console. log ( bNum)
}
}
return obj
}
var obj = test ( )
obj. supply ( )
obj. sale ( )
闭包原理解析
function test ( ) {
var arr = [ ]
for ( var i = 0 ; i < 10 ; i++ ) {
arr[ i] = functioin ( ) {
console. log ( i)
}
}
return arr;
}
var myArr = test ( )
for ( var j = 0 ; j < 10 ; j++ ) {
myArr[ j] ( )
}
问题产生的原因是,数组中保存的函数在执行时读取了test中的i,这个i在经过循环之后被修改为10 了。所以要想办法保留住每次循环得到的i
function test ( ) {
var arr = [ ]
for ( var i = 0 ; i < 10 ; i++ ) {
( function ( j) {
arr[ j] = function ( ) {
console. log ( j)
}
} ) ( i)
}
return arr;
}
var myArr = test ( )
for ( var j = 0 ; j < 10 ; j++ ) {
myArr[ j] ( )
}
function test ( ) {
let arr = [ ]
for ( let i = 0 ; i < 10 ; i++ ) {
arr[ i] = function ( ) {
console. log ( i)
}
}
return arr;
}
let myArr = test ( )
for ( let j = 0 ; j < 10 ; j++ ) {
myArr[ j] ( )
}
实例在开发中的应用举例
< ! DOCTYPE html>
< html>
< head>
< meta charset= "UTF-8" >
< meta name= "viewport" content= "initial-scale=1, maximum-scale=1, user-scalable=no" / >
< title> test< / title>
< / head>
< body>
< ul>
< li> 1 < / li>
< li> 2 < / li>
< li> 3 < / li>
< li> 4 < / li>
< li> 5 < / li>
< / ul>
< / body>
< script type= "text/javascript" >
var oLis = document. querySelectorAll ( 'li' )
for ( var i = 0 ; i < oLis. length; i++ ) {
( function ( j) {
oLis[ j] . onclick = function ( ) {
console. log ( j)
}
} ) ( i)
}
< / script>
< / html>
闭包比较常见的写法
function Persion ( name) {
this. pname = name;
}
Persion. age = 11 ;
Persion. protoptype. say = function ( ) {
console. log ( 'hello,world' )
}
var p = new Persion ( 'ww' )
p. say ( )
var Persion = function ( ) {
var obj = new Object ( )
obj. aage = 11 ;
obj. say = function ( ) {
console. log ( 'say' )
}
return obj;
}
var p = Persion ( )
p. say ( )
var Persion = {
aage: 11 ,
say: function ( ) {
console. log ( 'say' )
}
}
Persion. say ( )
闭包的用途
结果的缓存
var CachedSearchBox = ( function ( ) {
var cache = { } ,
count = [ ] ;
return {
attachSearchBox : function ( dsid) {
if ( dsid in cache) {
return cache[ dsid] ;
}
var fsb = new uikit. webctrl. SearchBox ( dsid) ;
cache[ dsid] = fsb;
if ( count. length > 100 ) {
delete cache[ count. shift ( ) ] ;
}
return fsb;
} ,
clearSearchBox : function ( dsid) {
if ( dsid in cache) {
cache[ dsid] . clearSelection ( ) ;
}
}
} ;
} ) ( ) ;
CachedSearchBox. attachSearchBox ( "input" ) ;
用闭包模拟私有方法
var Persion = ( function ( ) {
var age = 0
function realAge ( val) {
age + = val
console. log ( 'age' , age)
}
return {
addAge: function ( age) {
realAge ( age)
} ,
decAge: function ( age) {
realAge ( age)
}
}
} ) ( )
Persion. addAge ( 10 )
Persion. decAge ( 2 )
console. log ( 'persion.age' , Persion. age)
var makeCounter = function ( ) {
var privateCounter = 0 ;
function changeBy ( val) {
privateCounter + = val;
}
return {
increment: function ( ) {
changeBy ( 1 ) ;
} ,
decrement: function ( ) {
changeBy ( - 1 ) ;
} ,
value: function ( ) {
return privateCounter;
}
}
} ;
var Counter1 = makeCounter ( ) ;
var Counter2 = makeCounter ( ) ;
console. log ( Counter1. value ( ) ) ;
Counter1. increment ( ) ;
Counter1. increment ( ) ;
console. log ( Counter1. value ( ) ) ;
Counter1. decrement ( ) ;
console. log ( Counter1. value ( ) ) ;
console. log ( Counter2. value ( ) ) ;