两个函数互相嵌套或者多个函数互相嵌套----闭包
闭包是指有权访问另一个函数的作用域中的变量的函数,创建闭包的常见方式,就是在一个函数内部创建另一个函数。
但凡是内部的函数保存在了外部,一定产生闭包。
关于内存泄露问题
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放(占空间),造成内存泄漏。
内存泄漏:占用的内存没有及时释放。内存泄露积累多了就容易导致内存溢出。
常见的内存泄露:
- 意外的全局变量
- 没有及时清理的计时器或回调函数
- 闭包
情况一举例:
// 意外的全局变量
function fn() {
a = new Array(10000000);
console.log(a);
}
fn();
情况二举例:
// 没有及时清理的计时器或回调函数
var intervalId = setInterval(function () { //启动循环定时器后不清理
console.log('----')
}, 1000)
// clearInterval(intervalId); //清理定时器
情况三举例:
function fn1() {
var arr = new Array[100000]; //这个数组占用了很大的内存空间
function fn2() {
console.log(arr.length)
}
return fn2
}
var f = fn1()
f()
f = null //让内部函数成为垃圾对象-->回收闭包
内存泄漏解决方法:
能不用闭包就不用,及时释放
f=null; // 让内部函数形成对象垃圾,回收闭包
function a(){
var num=100;
function b(){
num++;
console.log(num);
}
return b;
}
//把 b return出去之后(b到了全局),a算执行完了
var demo=a();
demo(); //b执行 // 101
demo(); // 102
function compare(){
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
当创建compare()函数时,会创建一个预先包含全局变量对象的作用域,这个作用域被保存在内部的[[scope]]属性中,当调用这个compare()函数时,会为函数创建一个执行环境,然后通过复制函数的[[scope]]属性中的对象构建起执行环境的作用域链。此后,又有一个活动对象被创建并被推入执行环境的作用域链的前端。compare()作用域链包含两个变量对象:本地活动对象,全局活动对象
多个函数和一个函数形成闭包,他们之间的变量可以共用
闭包作用
- 实现公有变量
eg:不依赖外部变量并且能反复还行的函数累加器
function add(){
var count=0;
function demo(){
count++;
console.log(count);
}
return demo;
}
var counter=add();
counter();
counter();
counter();
counter();
每调用一次,就在原有基础上加1
- 可以做缓存(存储结构)
function test(){
var food="apple";
var obj={
eatFood:function(){
if(food!=""){
console.log("I am eating "+food);
food="";
}else{
console.log("There is nothing");
}
},
pushFood:function (myFood){
food=myFood;
}
}
return obj;
}
var person=test();
person.eatFood(); // I am eating apple
person.eatFood(); // There is nothing
person.pushFood("banana");
person.eatFood(); // I am eating banana
- 可以实现封装,属性私有化
//立即执行函数解决闭包作用域的问题
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]();
}
//这是个函数都和test形成闭包
私有化变量:只有通过自己的方法才能访问,外部不能访问。
function Deng(name,wife){
var prepareWife="xiaozhang";
this.name=name;
this.wife="xiaoliu";
this.divorce=function(){
this.devorce=prepareWife;
}
this.changePrepareWife=function (target){
prepareWife=target;
}
this.sayPrepareWife=function(){
console.log(prepareWife);
}
}
var deng=new Dend('deng','xiaoliu');
console.log(deng.prepareWife); //undefined(外部访问)
console.log(deng.sayPrepareWife()); // xiaozhang(通过自己的方法访问)
- 模块化开发,防止污染全局变量【命名空间】
闭包的应用:
- 具有特定功能的js文件
- 将所有的数据和功能都封装在一个函数内部(私有的)
- 【重要】只向外暴露一个包含n个方法的对象或函数
- 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
方式一:
function my(){
//私有数据
var msg="Smyhvae Haha";
//操作私有数据的函数
function dosomething(){
console.log("dosomething()"+msg.toUpperCase());
}
function doOtherthing(){
console.log('doOtherthing()'+msg.toLowerCase());
}
//通过【对象字面量】的形式进行【包裹】,向外暴露多个函数
return{
dosomething1:doSomething,
doOtherthing:doOtherthing
}
}
在html文件中
var module=my();
module.dosomething1();
module.doOtherthing2();
方式二
(function(){
//私有数据
var msg = 'Smyhvae Haha'
//操作私有数据的函数
function doSomething() {
console.log('doSomething() ' + msg.toUpperCase())
}
function doOtherthing() {
console.log('doOtherthing() ' + msg.toLowerCase())
}
//外部变量是立即执行运行的匿名函数,我们可以把两个方法直接传给window对象
window.mymodule={
dosomething1=doSomething,
doOthing2:doOtherthing
}
}())