闭包
210315
1、引入
var btns = document.getElementsByTagName("button")
for(var i = 0,length = btns.length; i<length; i++){
var btn = btns[i]
//将btn所对应的下标保存在btn上
btn.index = i
btn.onclick = function(){
alert('第'+(this.index+1)+'个')
}
}
//利用闭包
for(var i = 0,length = btns.length; i<length; i++){
(function (i){//局部变量i
var btn = btns[i] //局部变量i
btn.onclick = function(){
alert('第'+(i+1)+'个')
}
})(i)//读全局变量i
}
2、理解闭包
-
如何产生闭包?
- 当一个嵌套函数的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
function fn1(){ var a = 2 //Local中的Scopes的Closure var b ='abc' function fn2(){ //执行函数定义就会产生闭包(不用调用内部函数) console.log(a) } fn2() } fn1()
-
闭包到底是什么
-
使用chrome调试查看(Local中的fn2:Scopes的Closure)
-
理解1:闭包是嵌套的内部函数
-
理解2:包含被引用变量(函数)的对象
-
注意:闭包存在于嵌套的内部函数中
-
-
产生闭包的条件
- 函数嵌套
- 内部函数引用了外部函数的数据
3、常见的闭包
-
将函数作为另一个函数的返回值
-
将函数作为实参传递给另外一个函数调用
//产生几个闭包,看外部函数调用的次数 //将内部函数作为外部函数的返回值,此函数产生了一个闭包 function fn1(){ var a = 2 //设断点 function fn2(){ a++ //设断点 console.log(a) } return fn2 } var f = fn1() f() //3 f() //4 function showDelay(msg,time){ setTimeout(function(){ alert(msg) },time) } showDelay('nidjis',2000)
4、闭包的作用
- 使函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
- 让函数外部可以操作(读写)到函数内部的数据(变量/函数)
- 函数执行完后,函数内部声明的局部变量是否还存在?一般不存在,存在于闭包中的变量可能存在
- 在函数外部能直接访问函数内部的局部变量吗? 不能,但是通过闭包可以让外部操作内部变量
function fn1(){
var a = 2 //设断点
function fn2(){
a++ //设断点
console.log(a)
}
function fn3(){
a--
console.log(a)
}
return fn3
}
/*如果没有变量保存fn1函数返回的函数,即执行完fn1后,fn3被释放,因为没有引用*/
var f = fn1()
f() //1
f() //0
5、闭包的生命周期
- 产生:在嵌套内部函数定义执行(创建函数对象)完时就产生了(不是在调用)
- 死亡:在嵌套的内部函数成为垃圾对象时
function fn1(){
//此时闭包已经产生,因为函数提升,内部函数对象已经创建了
var a = 2
function fn2(){
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() //3
f() //4
f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)
function fn1(){
var a = 2
//此时闭包已经产生,(定义执行完后)
var fn2 = function (){
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() //3
f() //4
f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)
6、闭包的应用_自定义js模块
- 具有特定功能的js文件
- 将所有的数据和功能都封装在一个函数内部(私有的)
- 只向外暴露一个包含n个方法的对象或函数
- 模块的使用,只能通过模块提供暴露的对象调用方法来实现对应的功能
//1、
function myModule(){
//私有数据
var msg = 'Hello'
//操作数据的函数
function doSomething(){
console.log('doSomething():' +msg.toUpperCase())
}
function doOtherthing(){
console.log('doOtherthing():' +msg.toLowerCase())
}
//向外暴露对象(给外部使用的方法)
return{
doSomething:doSomething,
doOtherthing:doOtherthing
}
}
var module = myModule()
module.doSomething()
module.doOtherthing()
//2、
(function(window){
//私有数据
var msg = 'Hello'
//操作数据的函数
function doSomething(){
console.log('doSomething():' +msg.toUpperCase())
}
function doOtherthing(){
console.log('doOtherthing():' +msg.toLowerCase())
}
//把向外暴露的东西,保存在window对象中
window.myModule2 = {
doSomething:doSomething,
doOtherthing:doOtherthing
}
})(window) //两个小括号中的window,为了方便代码压缩
myModule2.doSomething()
myModule2.doOtherthing()
7、闭包的缺点及解决
- 缺点
- 函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
- 容易造成内存泄漏
- 解决
- 能不用闭包就不用
- 及时释放 赋值为null
function fn(){
var arr = new Array[100000]
function fn2(){
console.log(arr.length)
}
return fn2
}
var f = fn1()
f()
f = null //让内部函数成为垃圾对象--回收闭包
8、内存溢出与内存泄漏
-
内存溢出
- 一种程序运行出现的错误
- 当程序运行的内存超过了剩余的内存时,就会抛出内存溢出的错误
var obj = {} for(var i = 0; i < 10000; i++){ obj[i] = new Array(100000000) }
-
内存泄漏
- 占用的内存没有及时释放
- 内存泄漏积累多了就容易导致内存溢出
- 意外的全局变量
- 没有及时清理的计时器或回调函数
- 闭包
//意外的全局变量,用var声明变量 function fn(){ //var a = new Array(10000000) a = new Array(10000000) console.log(a) } fn() var interval = setInterval(function(){//启动循环定时器后不清理 console.log('------') },1000) //clearInterval(interval) //闭包 function fn1(){ var a = 4 function fn2(){ console.log(++a) } return fn2 } var f = fn1() f() //f = null
9、闭包相关代码
var name = "The Window"
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name
}
}
}
alert(object.getNameFunc()()); //The Window
//闭包
var name = "The Window"
var object = {
name : "My Object",
getNameFunc : function(){
var that = this
return function(){
return that.name
}
}
}
alert(object.getNameFunc()()) //My Object
function fun(n,o){
console.log(o)
return{
fun:function(m){
return fun(m,n)
}
}
}
var a = fun(0)
console.log(a,a.fun(1), a.fun(2),a.fun(3))//undefined,0,0,0 a.fun()执行了外部a函数,创建了新的闭包,但没有值保存,产生的闭包立马消失,o一直为0
var b = fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2
console.log(b)
var c = fun(0).fun(1)
console.log(c, c.fun(2), c.fun(3))//undefined,0,1,1