典型的闭包

典型的闭包是一个函数A内声明并返回一个函数B供外部使用,函数B内用到了A内部的局部变量或者形参。外界对A函数内变量的引用导致A作用域不能被释放,构成一个闭包。

  1. function Counter(n) {
  2. let num = 0
  3. function add(){
  4. num += n
  5. console.log(num)
  6. }
  7. return add
  8. }
  9. let addOne = Counter(1)
  10. addOne() //1
  11. addOne() //2

image.png

几个闭包

  1. function Counter() {
  2. let num = 0
  3. return function() {
  4. num++
  5. console.log(num)
  6. }
  7. }
  8. let count1 = Counter()
  9. count1() //1
  10. count1() //2
  11. let count2 = Counter()
  12. count2() //1
  13. count2() //2

换一种写法

  1. const sum = a => b => a + b
  2. console.log(sum(3)(4))

更宽泛的闭包

更宽泛的场景是函数B不一定直接返回,只要B能够再次被调用,都构成闭包。比如A返回的是一个对象,而函数B是对象的属性。或者函数B能在setTimeout延时结束时的触发。

返回一个对象

  1. function Counter() {
  2. let num = 0
  3. return {
  4. add(){
  5. num++
  6. console.log(num)
  7. }
  8. }
  9. }
  10. let counter = Counter()
  11. counter.add()
  12. counter.add()

什么都不返回

  1. function Counter() {
  2. let num = 0
  3. function add(){
  4. num ++
  5. console.log(num)
  6. }
  7. window.add = add
  8. }
  9. let counter = Counter()
  10. add()

setTimeout

  1. function Counter() {
  2. let num = 0
  3. function add(){
  4. num ++
  5. console.log(num)
  6. }
  7. setTimeout(add, 1000)
  8. }
  9. let counter = Counter()

闭包的作用

  1. 用来暂存“当时”的状态;
    2. 用来“封装”一些数据

封装数据/模块模式/IIFE

  1. const cache = (() => {
  2. const store = {}
  3. return {
  4. get(key) {
  5. return store[key]
  6. },
  7. set(key, val) {
  8. store[key] = val
  9. },
  10. remove(key) {
  11. delete store[key]
  12. }
  13. }
  14. })()
  15. console.log(cache) //{get: ƒ, set: ƒ, remove: f}
  16. cache.set('name', '饥人谷')
  17. cache.get('name'); // '饥人谷'
  18. cache.remove('name')

暂存数据/高阶函数/Curry

  1. const makeUrl = domain => path => `https://${domain}${path}`
  2. const makeJrgUrl = makeUrl('jirengu.com')
  3. const makdeXdmlUrl = makeUrl('xiedaimala.com')
  4. const url1 = makeJrgUrl ('/about')
  5. const url2 = makdeXdmlUrl ('/index')

相关面试题

题1:以下代码输出什么?如果想输出 0、1、2、3、4 需要怎样修改

  1. for(var i=0; i<5; i++){
  2. setTimeout(function(){
  3. console.log('clock:' + i )
  4. }, 0)
  5. }

题2:以下代码输出什么

  1. function Counter(n) {
  2. let num = 0
  3. function add(){
  4. num += n
  5. console.log(num)
  6. }
  7. return add
  8. }
  9. let counter1 = Counter(1)
  10. counter1()
  11. counter1()
  12. let counter2 = Counter(2)
  13. counter2()
  14. counter2()

题3:当点击li时输出什么?

  1. <ul>
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. </ul>
  7. <script>
  8. let $arrLi = document.querySelectorAll('li')
  9. for(var i=0; i<$arrLi.length; i++) {
  10. $arrLi[i].onclick = function() {
  11. console.log(i)
  12. }
  13. }
  14. </script>

题4:把函数 sum(a, b, c) 变成 sum(a)(b, c) 的形式。

function sum(a, b, c) {
  return a + b + c
}

题5:补全代码,把函数fn(a, b, c) 的调用形式变成 fn(a)(b)(c) 的调用形式。 fn的参数个数不定。

function sum(a, b, c, d) {
  return a + b + c + d
}
function curry(fn) {
  //补全
}

let newSum = curry(sum)
newSum(1)(2)(3)(4)

答案

题1

//方法1
for(let i=0; i<5; i++) {
  setTimeout(() => {
    console.log('clock:' + i )
  }, 0)
}

//方法2
for(var i=0; i<5; i++) {
  ((i) => {
    setTimeout(() => {
      console.log('clock:' + i )
    }, 0)  
  })(i)
}

//方法3
for(var i=0; i<5; i++) {
  setTimeout(((i) => () => {
    console.log('clock:' + i )
  })(i), 0)
}

题2

输出 1 2 2 4

题3

for(let i=0; i<$arrLi.length; i++) {
  $arrLi[i].onclick = function() {
    console.log(i)
  }
}

for(var i=0; i<$arrLi.length; i++) {
  ((i) => {
    $arrLi[i].onclick = function() {
      console.log(i)
    }      
  })(i)
}

for(let i=0; i<$arrLi.length; i++) {
  $arrLi[i].onclick = ((i) => function() {
    console.log(i)
  })(i)
}

题4

function sum(a) {
  return function(b, c) {
    return a + b + c
  }
}

const sum = a => (b, c) => a + b + c

题5

function sum(a, b, c, d) {
  return a + b + c + d
}
function curry(fn) {
  return function curried(...args) {
    if(args.length >= fn.length) {
      return fn(...args)
    } else {
      return function(...args2) {
        return curried(...args.concat(args2))
      }
    }
  }
}

let newSum = curry(sum)
newSum(1)(2)(3)(4)
newSum(1)(2,3)(4)

若愚@饥人谷 | 饥人谷系统班 | 写代码啦