3-闭包定义理解,内存模型,内存泄漏

130 阅读3分钟

[[2022-08-08]]

函数是一等公民

​ 函数可以作为参数传递,也可以作为返回值(很灵活)

function foo(aaaaa) {
  aaaaa()
}

function bar() {
console.log("bar")
}

foo(bar)

学过前两节后这个例子一下就理解了,这里就是把函数的引用地址当作参数传递过去了

函数作为返回值:

function foo (){
  function bar () {
    console.log("bar")
  }
  return bar    //注意不要带(),带的话会执行一次再返回
}
var fn = foo()  //带()就是执行一下得到bar地址再赋值,不带括号就是直接给foo函数的地址了
fn()

这个想了想才理解

function makeAdder(count) {
  function add (num) {
    return count + num
  }
  return add
}
var add5 = makeAdder(5) //这里带括号了,相当于执行了一下makeAdder(5),结果是add函数地址,所以add5就是add函数,count已经确定死是5了,就是add5在内层

console.log(add5(2))//所以这里就是相当于给内层的add的num传入2

42行的var add5 = makeAdder(5)这里函数已经调用完了,count应该销毁,但是这里没有销毁,就是因为存在闭包

高阶函数

有个函数,如果这个函数接收其他函数作为参数,或者自己返回另一个函数作为返回值,那这个就是高阶函数。

js中常用的高阶函数

[[2022-08-08]]16:25,暂停
[[2022-08-09]]12:10,继续

数组的filter方法

数组的filter方法

在filter里面传个函数,自己写的判断函数,必须返回true或false,用来给filter判断当前元素要不要放入过滤后的新数组
数组里有几个元素,filter就执行几次你给的函数。

map函数

forEach

find/findIndex

reduce -累加

nums.reduce( function (preValue, item) {    //preValue是上一次返回的结果
  return preValue + item
} , initalValue)    //这里有一个初始化的值

闭包

定义

emm,确实不好理解

[[2022-08-09]]今天看到了第三集1小时30分处
[[2022-08-10]] 开搞开搞,现在看个2.5h

上面讲的这个函数👇

function foo() {
    var name = "foo"
    function bar () {
        console.log("bar", name)
    }
    
    return bar
}

var fn = foo()
fn()

这里的bar和name引用就组成了闭包

执行完var fn = foo()以后,foo的栈内存里的函数执行上下文会删掉,堆内存里的AO按理来说应该也删掉,但是这时他没删,后来的fn仍然能访问foo的AO里的name,这时bar函数和它带的name引用就组成了闭包i

闭包和函数的最大区别在于,当捕捉闭包的时候,它的自由变量也会被确定,这样即使脱离了捕捉时的上下文,它也能照常运行。

总结

一个最基本的普通函数(里头是空的)算不算闭包?
广义来说(可以访问):JavaScript中所有函数都是闭包
狭义来说(有访问到):如果JavaScript函数有访问外层作用域的变量,是闭包

内存

函数执行过程的内存

var message = "hello"
function foo (){
    var name = "foo"
    var age = 18
    
    function bar() {
    	console.log("name")
    	console.log("age")
	}
    
    return bar
}

var fn = foo()
fn()

为什么foo执行完以后不会销毁AO呢?
因为里面的bar被返回给了全局的fn变量,这时候可以从根(全局变量)出发一直引用到AO那里,就不会被销毁(看前面的GC垃圾回收那里的标记清除法)

闭包的内存泄漏

像上面这种情况,从根部开始有引用指着,那GC就不能回收它了。同时如果只需要用到一次的话,那用完这一次以后他也不能被GC回收,这时候就叫做内存泄漏(虽然我也不知道为啥叫作“泄漏”,感觉不够直观,我觉得应该是存在未清理的垃圾的意思才对)

怎么解决呢?直接去掉引用就可以了,fn = null

如果后续还要继续用的话,那就不算是内存泄漏了,泄不泄漏主要看后面还用不用。