1

温馨提示:作者的爬坑记录,对你等大神完全没有价值,别在我这浪费生命
温馨提示-续:本文(maybe)将会成为一篇笔记类型的文章,记录闭包具体的应用方式
温馨提示-再续:本文(maybe)存在错误,会慢慢改进的,请不要把我说的当真

在上一篇博文 javascript闭包不完全探索记录01:闭包?啥馅的?- lskrat 中,对javascript中闭包本身进行了研究和学习,并取得了一定的成果(知道了老王私房钱藏哪了)

接下来,按照面试官的思路,他不会问你一个没有用的东西啊,闭包既然被广泛的提及则必然(maybe)有其存在的价值和意义。

所以我不禁产生了疑问,这货到底干啥的?闭包要是如此重要,为啥我能够在不理解的情况下就干了这么多前端开发?

下面就(逐渐)慢慢列出来吧

获取函数内部属性

在上文提到的博文中已经有所提及,因为javascript本身的作用域链特性,外部无法调用内部的属性,所以当我们希望调用一个内部变量的时候(也不知道是什么时候)可以利用闭包来建立外部与函数内部的联系,举个例子

function testClosure(){
    var innerInfo = "lskrat"
    return function(){
        return innerInfo
    }
}
console.log(testClosure()())//lskrat

通过在外部调用testClosure的返回函数,成功的get到了他的内部属性

保持变量的保存在缓存中

这要从一个经典的误会说起

    function testClosure(){
        var funcs = [];
        for(var i = 0 ; i < 5 ; i++){
            funcs[i] = function(){
                return i
            }
        }
        return funcs
    }
    console.log(testClosure()[0]())//5
    console.log(testClosure()[1]())//5

乍看之下,可能会觉得上面的运行结果有问题,按照上文代码的大概含义应该的到的结果应该是根据调取不同的返回函数得到不同的i值才对,可最终得到的都是5,显然事情不是这么简单的

我们来对console.log(testClosure()[0]())进行分析,看看这句话都干了什么,首先调用了testClosure()这个函数,函数内部的for循环开始工作,生成了一个由函数组成的数组funcs,这一步结束之后,for循环中的i就已经是5了,而且由于返回的funcs中调用了内部变量i,所以i=5就一直被存在了缓存之中没有被释放,此时再执行testClosure()[0]相当于调用了funcs[0],不过无论调用的是funcs中的哪一个函数,其实都是要返回i的值,而func[n]中的i并没有在循环中被直接赋予循环时i对应的值,而只是一个变量的引用,这个引用就是那个被存在缓存之中的5,所以最后的结果就都是5了。

那我们怎样才能让这个代码正常(按照我们的想法)呢?
上面的写法之所以结果都是5主要是因为在构建函数func[n]的时候,所指向的i的值并没有存在于一个闭包中,所以如果我们写一个闭包呢,写一个内部函数,调用i,将它的值封在一个闭包中,具体写法如下

    function testClosure(){
        var func = []
        function testInner(j){
            func[j] = function(){
                return j
            }
        }
        for(var i = 0 ; i < 5 ; i++){
            testInner(i)
        }
        return func
    }

    console.log(testClosure()[4]());//4
    console.log(testClosure()[2]());//2

为什么可以了?原因就在与这里出现的testInner函数提供了一个新的作用域及变量,在执行的过程中,每当生成一个func[n]与之对应的j都会因为作用域链的原因,连同其对应的值被“锁住”与func[n]一起形成闭包,所以其中对应的i值就被保留了下来

之前没用过很可能是我一直都在使用各种已经被各位大神封装的很好的js库了吧,从JQuery到Vue我欠原生js一个闭包


lskrat
478 声望43 粉丝

能不能借我个谱靠靠