闭包,今天一绝高下也一绝生死!

288 阅读4分钟

为什么会有这篇文章

每次面试都会被问什么是 闭包,但是每次都是一个外部能访问函数内部变量,或者保存函数内部变量状态这样的答案混过去了。可能面试管知道我不了解闭包也没有难为我,也可能面试官自己都没玩明白闭包就是问一下意思意思走个过场。因为闭包这个算是一个比较基础的东西,并且做开发这么常时间都没有真正理解(虽然不常用),曾经也写过关于闭包的文章,但是也是属于自己骗自己那种,强行去理解这个概念(还理解错了),今天花了点时间重新学习了一下闭包,也问了多个大佬,可TM算整明白这到底是怎么一回事儿了!

理解闭包的所需要的知识

函数作用域以及作用域链条
按照类型引用按值引用
js垃圾回收机制

函数作用域以及作用域链

这一块没有什么好说的,只需要知道函数引用函数内部变量会向上(当前外部作用域)去查找,找到了就拿来使用(这一块不做过多解释)

基本数据类型&&引用数据类型

在内存中,变量为基本数据类型的都是以变量名+变量存在栈内存中,而引用数据类型可以理解成栈内存中变量名+引用地址(就是保存引用类型本身的内存地址)+堆内存中当前引用类型本身 引用数据类型(只要tpeyof 变量名为 object 都是引用数据类型)

js垃圾回收机制

这个也不需要做太多解释,为了理解闭包这一块我们可以只理解其中这一个概念,如果一个引用类型没有指针指向的话,那么内存就会像一个渣女一样把它抛弃 看段代码理解一下

let obj  = {
    name : 'js'func(){
        console.log(this.name)
    }
}

obj = null      //因为链接obj 和 {
      name : 'js'func(){
        console.log(this.name)
}这个对象的指针被消除了,那么 
{ name : 'js'func(){
        console.log(this.name)
}
它就会像一个老实人一样被抛弃,在堆内存中永远消失

有了这些前置知识再去了解闭包才能做到真正的了解

闭包

简单闭包例子

function func(){
    var a = 1
    return function(){
        console.log(++a)
    }
}
let aFunc = func()
aFunc()     //2
aFunc()     //3
aFunc()     //4

这个例子可以看出,我在函数内部return了一个匿名函数(就是我们刚才说的引用类型),由于通过 let aFunc = func(),这个时候func()会被执行一次,而且有了一个aFunc这个变量名和reurn出来的function,并且给这个匿名函数被赋予了内存地址,不仅return那个匿名函数被保存,而且外部的a变量也会被保存(但是第二次执行aFunc()的时候不会再去执行var a = 1,因为保存的是function(){ console.log(++a) }这个匿名函数所以aFunc()执行的也是它,但是它需要a这个变量的时候心里是有点逼数的,会直接去通过作用域链去外层拿,这样每次拿到就是外层的那个a并且改变的也是它外层的那个a,上述行为就可以起到一个闭包的效果(函数内部局部变量被保存)

function func (){
    var a = 1
    return ++a
}
let aFunc = func()
aFunc()     //2
aFunc()     //2
aFunc()     //2

这种情况为什么不会出现嘛,它也被引用了,但是到每次执行的时候都会去从头到尾执行var a = 1,所以a会被上一步操作aFunc()的值不会被储存

总结

闭包其实就是一个手法,如果在基本功扎实的情况下去理解这个东西就很好理解,它只是一种手法来达到的一个效果,就和事件节流一样,并不是一个新的知识点,所以基本功不好的情况下,还是好好的根据需要的知识点把基本功打牢了再来学习这一块可能会达到事半功倍的效果