4

记一道闭包题目

 3 years ago
source link: https://segmentfault.com/a/1190000038857131
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

记一道闭包题目

今天遇到一道经典的闭包内存泄漏问题,一下还是很难说的很清楚,这里重新理一下闭包的逻辑。

        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讨论


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK