2

之三:关于闭包和递归

1. 开篇

这一期本来是打算写闭包的,但是无意中看到《JavaScript高级程序设计》中闭包的前一章就是递归。
所以拿出来一起讲一下吧!

我觉得闭包算是笔试面试中常考的,当面试官问道闭包的时候。或许人人都会说上:从表象上看,闭包是内部函数引用外部函数的变量,导致内部函数引用的变量不会被释放。即使外部函数被销毁时,变量依然驻留在内存中!
可是大家真的懂这句话的意思吗(在深入了解之前,我也不明白)
今天就让我们来好好了解一下:

2. 闭包的原理

先看一段代码:


// 需求时是一秒钟之后,在控制台依此输出1-10
function numberLog() {
    for (var i = 1;i <= 10;i++) {
        setTimeout(function () {
            console.log(i)
        }, 1000)
    }
}
numberLog();

大家觉得上面的代码,能实现预期的需求吗?
当然不能,代码的执行速度很快,我们循环了十次,生成了十个setTimeout(function(){console.log(i)}, 1000)
然后当一秒钟过去了,i早就变成11了,所以最后就会输出10个11

那么怎么改进呢?
看这段代码:

function numberLog() {
    for (var i = 1;i <= 10;i++) {
        (function (count) {
            setTimeout(function () {
                return console.log(count)
            }, 1000)
        })(i)
    }
}
numberLog();

这次再看一下,在控制台上会输出1-10
这是为什么?其实看不懂也没有关系,就是简单的举了一个闭包的应用场景。

下面具体说一下,只需要记住以下几点:

  • 当一个函数执行时,全局会为这个函数做两件事:1.构建一个独立的函数环境 2.把全局的变量用作用域链的形式推给这个函数,换句简单的话说就是让这个函数可以访问到它外层定义的变量,并可以一层一层的向外引用
  • 如果一个函数里面嵌套了一个函数,并且这个内部函数引用外层函数的变量,那个这个变量就不能在外层函数结束后被释放(正常是函数调用完,环境和变量就都会被释放),因为不知道内部函数在什么时候就会被调用。

那上面这个例子是怎么回事呢?
我们可以看到在循环代码内我们执行了一个函数立即调用,并且返回一个console.log(XX)
由于立即调用的这个函数引用了外部函数numberLog的变量i,因此i从1-10都不会被释放,都会在内部形成一个闭包空间。
当一秒钟过去,还是会打印出 1-10

不知道这么说,你明白没有,不太懂的话请看书《JavaScript高级程序设计》第七章闭包那一节。

3. 闭包练习题

这个板块会实时补充的

4. 关于递归

其实说到递归,主要就是要说callee这个的用法,callee其实主要就是调用自己的外围函数,并且可以传参。
下面我们来看一个题(我面试百度时的题):

// 用setTimeout来模拟setInterval

先留个悬念哈!

5. 最后

今天是周日,下周会有一个百度糯米的面试!现在感觉自己的js的基础有些薄弱,
所以下一节会说一下js原生的dom操作,一起加油哟!

欢迎大家指出不足和意见,我会虚心接受


bradwang
174 声望41 粉丝

既迷茫又渴望,就是一个普普通通的程序员