复习Javascript专题(二):闭包,内存,以及垃圾回收机制

1.什么是闭包?闭包有啥特性以及存在什么问题?

概念:闭包是指有权访问另一个函数作用域中的变量的函数。下面的outer就形成了一个闭包:
function outer(){
    const name='nagi';
    return function inner(){
        console.log(name);
    }
 }
let p=outer();
}
let p=outer();

一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局执行环境中的变量对象,但闭包有所不同。
当outer()执行完后,因为inner函数的作用域链在引用outer的活动对象,所以它并不会被销毁,而是仍然留在内存中,
除非inner函数也销毁它的活动对象才会被销毁。比如使p=null;

特性: 由上面的代码可以得出以下几个特性:

a. 函数嵌套函数,作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
b. 函数内部可以引用外部的参数和变量。
c. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区,所以参数和变量不会被垃圾回收机制回收。

优点:

 a. 减少全局变量的污染
 b. 可以有私有变量的存在
function counter(){
    let n=0;
    function add(){
        n++;
       console.log(n);
    }
    return {n:n, add:add}
}
const c1=counter();
const c2=counter(); // 它和c1分别存入了不同的堆内存中
c1.add(); // 1
c1.add(); // 2
c1.n;     // 0 // 此处的n是基本类型,除非重新赋值,否则不会变!
c2.add(); // 1 c1和c2互不干涉,都有自己的新的作用域链和新的私有变量
注意!!父函数每次调用会产生新的闭包

缺点(问题)

a.常驻内存,增加内存使用量。
b. 使用不当会很容易造成内存泄露。
另:闭包的多种写法可以参照这里: JavaScript闭包(closure)

2.js中的垃圾回收机制

 原理:js中有自动回收管理内存机制,它的原理是会定期(周期性地)找出那些不再继续使用的变量,然后释放其占用的内存。

内存管理:

1. 分配内存(不管是基本类型还是引用类型)
2. 使用内存(对变量,函数等读取或写操作)
3. 释放内存(使用垃圾回收机制回收内存)

回收方式

1.引用计数
**含义:**跟踪记录每个值被引用的次数。
**工作机制:**
    当声明一个变量并将一个引用类型值赋给它时,则这个值的引用次数就是1;
    如果同一个值又被赋给另一个变量,则该值的引用次数加1;
    相反,如果包含对这个值引用的变量又被赋了其他值,则这个值的引用次数减1;
    当这个值的引用次数为0时,则说明没有办法再访问这个值了;
    这样,当垃圾收集器下次再运行时,便会释放这种引用次数为0的值所占的内存。

问题:

这种方式有一个严重的问题,即“循环引用”。
意思是对象A中包含一个指向对象B的指针,而对象B也包含一个指向对象A的指针,
这样当函数执行完毕后,因为其引用也就永远不会为0,所以对象A和B将继续存在,
如果对象所在函数被重复调用,就会导致大量内存得不到回收。
 function problem(){
     let objA=new Object();
     let objB=new Object();

     objA.someOtherObj=objB;
     objB.antherObj=objA;
 }
2.标记清除(常用方式)
原理:垃圾回收器会在运行时给存储在内存中的所有变量加一个标记。
(当变量进入环境时,就交这个变量标记为“进入环境”。而当变量离开环境时,则将其标记为“离开环境”。)

然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。

而在这些完成之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。

最后,垃圾回收器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
闭包在编程有很多应用场景,以下是一些常见的例子: 1. 数据封装和私有变量:闭包可以用来创建私有变量,从而实现数据封装和保护。这在模块化编程和面向对象编程非常有用。 2. 函数工厂:闭包可以用来创建一系列相关的函数,这些函数共享相同的外部变量。这在创建类似于Python的装饰器或JavaScript的高阶函数时非常有用。 3. 延迟执行和计时器:闭包可以用来实现延迟执行和定时器功能。例如,在JavaScript,setTimeout和setInterval函数使用闭包来实现延迟执行和定时器功能。 4. 记忆化(Memoization):闭包可以用来实现记忆化,即缓存函数的计算结果,以便在后续调用重用。这可以提高函数的性能,特别是在处理计算密集型任务时。 5. 事件处理和回调函数:在JavaScript等事件驱动的编程环境闭包常用于实现事件处理和回调函数闭包可以捕获事件处理函数的上下文,使得事件处理函数可以访问其所需的外部变量。 6. 部分应用(Partial Application)和柯里化(Currying):闭包可以用来实现部分应用和柯里化,这是一种将多参数函数转换为一系列单参数函数的技术。这可以简化函数调用,使得代码更加简洁和可读。 7. 实现迭代器和生成器:在某些编程语言,例如Python和JavaScript闭包可以用来实现迭代器和生成器,这是一种用于遍历数据结构的高效方法。
07-14

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值