闭包
闭包:具有作用域的代码块就是闭包
1.闭包的使用场景
1.1
一个函数返回函数内部的工具函数,外部通过工具函数间接访问函数局部变量的过程
function alipay() {
var money=1000
//不能让函数之外的代码直接操作money 但是可以让自己的内部工具操作 然后返回这个工具
function tool () {
money-=20
}
return tool
}
function meituan () {
// var m=alipay()
// m=m-20
// console.log(m)
var aplitool=alipay()
aplitool()
}
meituan()
1.2
利用函数自调用,每次调用内部的局部变量或者形参都是独立的 来保存一些临时数据
var arr=[]
for(var i=0;i<5;i++){
(function(index){
arr[index]=function fn(){
console.log(index)
}
// divs[index].onclick=function(){
// // divs[index]
// }
})(i)
}
arr[2]()//5
1.3
利用函数的独立作用域 来生成业务代码块 内部的变量相互不冲突污染全局变量
(function(){})();
(function(){})();
2.闭包的优点及缺点
2.1 闭包的优点
1.函数内部的变量 想要被外部程序使用 但是语法决定了外部不能使用,可以利用闭包解决
2.一些临时数据 比如for循环的i的值 希望延时业务中使用 可以使用闭包把临时数据保存到局部作用域中
3.防止变量污染 可以用闭包把一些业务变量放在局部作用域中
2.2闭包的缺点及其解决办法
2.2.1 闭包的缺点
虽然闭包好用 可以解决很多问题 但是使用不当的话就会有一些致命的问题:内存泄漏
内存泄漏:浏览器运行网页 就会执行js代码,引用数据会在内存中占用内存空间,如果有一个对象创建了 而且占用了内存 却没有什么业务使用(想用都用不了) 这种情况就是内存泄漏
系统会定期查看我们的js执行情况,观察创建的对象有没有可能会被使用,如果没有可能 就释放内存,每一个对象都有"人"引用它 如果引用的"人"数为0就释放内存
代码演示:
引用计数:
var obj={}//引用计数为1
var arr=[]
arr[0]=obj//引用计数为2
function fn (a) {
//var a=obj//引用计数为3
var b=a//引用计数为4
}
fn(obj)
引用计数为2
无内存泄漏:
function fn () {
var obj={age:20}
console.log(123)
console.log(123)
}
fn()//调用时 内存中有一个对象var obj={age:20}
调用完毕fn函数,内部的变量没有谁再能访问,对象obj释放,因此没有导致内存泄漏
内存泄漏:
function fn () {
var obj={age:20}
function tool () {
return obj.age
}
return tool
}
// var re=fn()
// console.log(re())
var re=fn()//fn()调用完毕 内部的obj对象没有释放
console.log(re())
2.2.2 内存泄漏的解决办法
内存泄漏的解决方案:
1.尽量避开 不要使用闭包
2.在可能存在泄漏的地方把标识符引用为null
function fn() {
var obj = {
age: 20
}
function tool() {
return obj.age
}
return tool
}
var re = fn()
re=null;
回调函数
先有需求,再设计函数。将外部函数传入内部,是个特殊的闭包.
function fn (arg) {
// console.log(arg)
// console.log(arg[2])
// console.log(arg.name)
// console.log(arg)
var b=100
arg(b)
}
// fn(100)
// fn("hello")
// fn([10,20,30])
// fn({name:'karen'})
function fm(c){console.log(123,c);var a=20;}
fn(fm)
//callback==>c钩子函数
案列
function axios(selector,url,callback){
console.log(this)
var res={tag:selector,data:url}
callback("200",res)
}
var obj={
el:"#app",
mounted:function(){
var self=this
axios("box1","http://www.baidu.com",function(arg1,arg2){
console.log(arg1,arg2,this,self)
})
}
}
obj.mounted()
分析:
1.obj.mounted()调用函数,调用者为obj对象。var self=this表示self为obj对象本身
2.axios()开始调用,调用者为window,console.log(this)打印window。
3.callback("200",res)开始调用回调函数function(arg1,arg2){console.log(arg1,arg2,this,self)},调用者为window,arg1=200,arg2=res={tag:"box1",date:"www.baidu.com"} ,this为window,self属性自身没有,去外层作用域寻找var self=this,slfe为obj对象本身