关于javascript:记一道闭包题目

42次阅读

共计 767 个字符,预计需要花费 2 分钟才能阅读完成。

题目

明天遇到一道经典的闭包内存透露问题,一下还是很难说的很分明,这里从新理一下闭包的逻辑。

        var t = null;
        var replaceThing = function() {
            var o = t
            var unused = function() {if (o)
                    console.log("hi")
            }
            t = {longStr: new Array(1000000).join('*'),
                    someMethod: function() {console.log(1)
                    }
                }
        }
        setInterval(replaceThing, 1000)

闭包剖析

闭包大家都晓得,重点从两个方面来了解:

  • 函数嵌套函数,内层函数援用了外层函数作用域下的变量,并且内层函数被全局环境下的变量援用,就造成了闭包。
  • 函数外部定义的所有函数共享同一个闭包对象。

所以,看到一个函数先确定其中的函数嵌套关系,再看是否内层函数援用了外层函数作用域下的变量,这道题目中,内层函数 unused 援用了外层函数 replaceThing 作用域中的变量 o, 这里就有了一个闭包对象,如果没有前面的t 对象,因为函数 unused 并没有被全局变量援用,这个闭包对象在函数执行完后就销毁了。

然而咱们看前面的代码,someMethod函数组成一个大对象被赋值给了全局变量 t,这里就合乎了定义“内层函数被全局环境下的变量援用”,然而很多人有疑难我这个办法里没有援用外层函数的变量啊,这里就正好合乎了第二条定义“函数外部定义的所有函数共享同一个闭包对象”,因而someMethod 函数跟 unused 共享了同一个闭包对象,隐式持有了变量 o 的援用,造成了一个 t -> someMethod -> o -> 上一次 t -> ... 的循环援用,造成了内存透露。

解决办法

切断这个循环援用也就是说切断 o 到上一次 t 的援用,即在函数知性最初加上 o = null 即可。

问题参考

题目
github 探讨

正文完
 0