你不知道的Chrome的闭包🐱‍🐉

413 阅读4分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

绝对不是标题党!

😢什么鬼,一次技术分享竟然搞出来俩种闭包 ?

当使用Chrome的控制台看到闭包的判断,我惊了,这还是我认识的闭包吗.....

一. Chrome里的闭包判断

直接上来就来个闭包demo看看

var m

function demo1() {
	var num = 10;
	function inner() {
		console.log(num) 
		debugger
	}
	m = inner;
}
demo1()
m()

让我们打开Chrome的控制台看一下

image.png ???什么鬼

难道不应该是inner的闭包吗 我赶紧翻开小书寻找一手

二. "教材"中的闭包

教材选自--《你不知道的JavaScript》上卷

image.png

  1. foo()函数的返回值,返回了内部函数bar()

  2. 外部定义了baz把foo()的返回值赋值给了它,外部调用了baz,实际上就是等于引用调用了内部函数bar()

  3. 那么这个引用bar()就被称为了闭包

😂 看到了这,已经是大无语事件了,到底哪种是对的呢?

其实并没有准确的判定闭包的定义,相比于教材上的判断,Chrome里面直接看到会更加直观一点把!

三. 说一下自己对于闭包概念的理解吧

我是看不懂教材上面的解释,可能我太笨了...

闭包的判定

当一个函数运行时形参或者其私有变量被内部函数所引用,满足这个条件时,那么这个函数就会形成闭包。

来个demo看看

对第一个demo 跟 不做引用的例子做个对比

var a,b

function demo1() {
	var num = 10;
	function inner() {
		console.log(num) // 对外部函数demo1的num进行了引用 
		debugger
	}
	a = inner;
}
demo1()
a()


function demo2() {
	var num = 10;
	function inner() {
		console.log("打印一下把") //没有引用任何变量,只做打印
		debugger
	}
	b = inner;
}
demo2();
b();

image.png

image.png

从两张图中就可以看出 闭包的判定 跟内部函数是否引用外部函数变量有关

当多个内部函数都存在时,只要有内部函数存在引用外部变量,其他内部函数共享外部函数的变量和形参

var a 
var demo3 = function(){

  let name = '标题党'
  function inner1(){
    console.log('我是第一个内部函数')
    debugger
  }

  function inner2(){
    console.log('我是第二个内部函数')
  }

  function inner3(){
    console.log(name)
    
  }
  a = inner1

  return inner3
}

demo3()
a()

image.png

四. 闭包使用不当带来的问题 划重点是** 使用不当 **

🤔别上来就闭包带来的问题!

看清楚标题再看下面,不是闭包带来的问题,是使用不当造成的内存泄漏情况。

先来个demo

<button onclick="onClick()">点我就能看到闭包泄漏</button>
<script>
 let result = []  
    function demo4 () {
        let arr = new Array(10000) 
        let num = 666
        function inner() {
            let name = '标题党'
        }       
        inner()       
        return arr     
    }
    function onClick() {
      result.push(demo4())        
    }  
</script>

操作方法:

1. 打开Chrome控制台点击性能页面,左侧圆圈代表开始录制,垃圾桶图标表示执行垃圾回收机制.

image.png

2. 点击录制,先执行一次垃圾回收(为了录制出来更好区分基准线),点击按钮,连续点击几次,本次以四次为例,在点击完按钮后, 重点来了 --最后一定要执行一次垃圾回收(模仿JS自动回收内存情况)

3. 展示效果如下,我们通过图中可以看出每次点击按钮,堆内存都会增加一个梯度,执行完四次之后,执行一次垃圾回收,发现梯度下降,但是堆内存没有完全消失,留了一部分梯度,这就是说明存在内存泄漏的情况

image.png

😁继续探索内存泄漏问题

看不懂英文的不会设置一下嘛~

操作方法:

点击内存(Memorize)页面,选择第二个选项(以时间轴的方式展示内存分配情况),点击开始,执行几次点击按钮事件,最后执行一次垃圾回收机制,效果如下方第二张图片.

image.png

image.png

😜定位内存泄漏问题

内存页面第一个选项点击开始时,如果报错的话,进无痕模式,先在性能页面录制重复一下操作,再到内存页面选择第一个选项,多试几次.

操作方法:

还是内存页面,点击选项第一个,点击下方拍摄快照.

下一步,重点来了,执行几次点击事件,重新执行一下拍摄快照,页面会出现两个快照

选择下方图片内红色框内的第三个选项,这个选项是只显示快照2和快照1的区别.

image.png

🤣这样我们就定位到了内存泄露的位置了

image.png

内存泄漏例子来自于 一文带你了解如何排查内存泄漏导致的页面卡顿现象

👌总 结

闭包其实在我们项目中无处不在的,模块化就是代表作之一.

合理使用闭包,你才能发现他的魅力,使用不当会造成内存泄漏的哦!

欢迎小伙伴们在评论区一起讨论!!