Wisdom a Web Developer

闭包与高阶函数

2019-07-08
wisdom

你真的了解闭包吗,你知道闭包在实际开发中有什么用么,闭包是否会造成内存泄漏呢。

如果你想了更进一步了解闭包,请接着往下看吧。

本文主要参考《JavaScript设计模式与开发实践》。

(一) 前言:

闭包是一个可以访问到其他函数内部变量的函数

闭包一直在前端圈内耳熟能详,甚至可以说是面试必考经典。

但在我的前端程序员生涯的很长一段时间里,我对闭包的印象就是,我们在们面试中常说的那句。

闭包是一个可以访问到其他函数内部变量的函数

随着开发项目的不断增加,经验的不断积累偶尔也会用到闭包,但对闭包的感知是零零碎碎不成体系的。于是有了总结闭包这个知识点的想法。

本文是我个人依据个人日常开发经验,网络查询资料,综合整理的一篇文章,希望能给大家带来一些帮助

(二) 闭包

首先直观来看闭包的确是我们在面试中常说的那句,闭包是一个可以访问到其他函数内部变量的函数。

为何会有上面那句话,细化来说个人认为理解两个点就好了,其一是变量的作用域,是二是变量的生命周期

1. 变量的作用域

首先函数内的变量是局部变量,在该函数外我们是无法访问到的(下面的例子解释了这一点)

    // 变量作用域演示
    
    var func = function () {
      var a = 1
      console.log('func', a) // 输出: func 1
    }
    
    func()
    
    console.log(a) // 输出: ReferenceError: a is not defined

作用域的概念我想大家都知道,就不详细叙述了。

2. 变量的生命周期

变量一般在函数执行完毕后如果没有额外引用,就被销毁了,下面的例子可以比较清晰的反应出这一点

    // 变量的生命周期
    
    let func = function () {
      let a = 0
      a++
      console.log('输出内容', a)
    }
    
    func() // 输出内容 1
    func() // 输出内容 1
    func() // 输出内容 1
    
    let func1 = function () {
      let a = 0
      return function () {
        a++
        console.log('输出内容', a)
      }
    }
    
    let funcClosure = func1()
    
    funcClosure() // 输出内容 1
    funcClosure() // 输出内容 2
    funcClosure() // 输出内容 3

为什么闭包中的变量没被销毁呢这个涉及到垃圾回收机制,即我们常说的标记清除引用计数

3. 面试常考

曾经面试喜欢考这样一道题目, 当然一般的题目给有序的DOM节点绑定click事件

onclick的事件是异步触发的, for循环以迅雷不及掩耳的速度执行完毕所以每次打印的是最终的数字

然而今天变量申明用 let, 这一问题得到了完美的解决, 下面的例子用setTimeout模拟异步执行

    // 面试常考题目: 问最后输出的是什么
    
    function closure() {
      for(var i = 0; i < 10; i++) {
        setTimeout(function () {
          console.log('输出内容', i) // 全部输出10
        }, 0)
      }
    }
    closure()
    
    // 老版解决方法
    
    function closure1() {
      for(var i = 0; i < 10; i++) {
        (function (i) {
          setTimeout(function () {
            console.log('输出内容', i)
          }, 0)
        })(i) // 最后输出1, 2, 3, 4, 5 ... 10
      }
    }
    closure1()

上一篇 关于HTTP缓存

下一篇 SMART原则

Comments

隐藏