今天复习js的时候又对闭包有些理解,趁现在热乎总结一下吧!
一、简单说一下闭包吧
按照我的理解,闭包分为两部分:函数+词法作用域。什么是词法作用域呢?即以变量声明定义的位置为参照,如果当前位置没有定义,就会访问父级定义的位置。闭包分为两种,广义上的闭包和狭义上的闭包,两者上的区别,在我看来就是广义上的闭包看着不像闭包,通常一般也不说它是闭包,但是实现上来说就是一个闭包;而狭义上的闭包,就是平常工作中会用到的闭包:函数嵌套函数,子函数引用了父函数的相关变量,会长期驻扎在内存中,缓存变量,但是就是因为长期驻扎在内存中,如果还不定时清理的话,会造成内存的泄露。
看一下广义上的闭包代码:
var a
=1000;
function fn1() {
alert(a
)
}
fn1()
二、闭包的应用场景和实现
function makeAdd(x
) {
return function(y
) {
return x
+y
}
}
function setFontSize(size
) {
return function() {
document
.body
.style
.fontSize
=size
+"px"
}
}
function makeHelp(help
) {
return function() {
console
.log(help
)
document
.querySelector('.help').innerHTML
=help
}
}
function init() {
var userInfo
=[
{id
:'username',helpText
:'请输入用户名'},
{id
:'email',helpText
:'请输入邮箱'},
{id
:'address',helpText
:'请输入地址'},
]
for(var i
=0;i
<userInfo
.length
;i
++) {
var item
=userInfo
[i
];
document
.getElementById(item
.id
).onfocus
=makeHelp(item
.helpText
)
}
}
init()
var Counter
=(function() {
var index
=0;
var add=function() {
return index
++;
}
var jian=function() {
}
return {
increment
:function() {
add()
},
getValue
:function() {
return index
;
}
}
})()
三、闭包的优点和缺点
长期驻扎在内存中,可以缓存数据可以隔离作用域,避免全局污染私有成员的存在
四、闭包的更好的解决方案
利用es6新增的块级作用域的特性:let const
var list
= document
.querySelectorAll('ul li')
for(let i
= 0; i
< list
.length
; i
++){
list
[i
].addEventListener('click', function(){
console
.log(i
)
})
}
利用自执行函数独立作用域,也是红宝书里推荐的写法
var list
= document
.querySelectorAll('ul li')
for(var i
= 0; i
< list
.length
; i
++){
(function(i
){
list
[i
].addEventListener('click', function(){
console
.log(i
)
})
}(i
))
}
利用事件委托机制(只适用于li内没有其余元素的情况)
var list
= document
.querySelector('ul')
list
.onclick= function(e
){
var e
= window
.event
||e
var target
= e
.target
||e
.srcElement
if(target
.nodeName
.toLowerCase()== 'li'){
console
.log([].indexOf
.call(document
.querySelectorAll('li'), target
))
}
}