闭包详解

时间:2021-6-19 作者:qvyue

典型的闭包

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

function Counter(n) {
  let num = 0
  function add(){
    num += n
    console.log(num)
  }
  return add
}
let addOne = Counter(1)
addOne() //1
addOne() //2

更宽泛的闭包

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

function Counter() {
  let num = 0
  return {
    add() {
      num++
      console.log(num)
    }
  }
}
let counter = Counter()
counter.add()
counter.add()

什么都不返回

function Counter() {
  let num = 0
  function add(){
    num ++
    console.log(num)
  }
  window.add = add
}

let counter = Counter()
add()

setTimeout

function Counter() {
  let num = 0
  function add(){
    num ++
    console.log(num)
  }
  setTimeout(add, 1000)
}

let counter = Counter()

闭包的作用

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

封装数据/模块模式/IIFE

const cache = (() => {
  const store = {}
  return {
    get(key){
      return store[key]
    },
    set(key, val){
      store[key] = val
    },
    remove(key){
      delete store[key]
    }
  }
})()
console.log(cache)//{get: ƒ, set: ƒ, remove: f}
cache.set('name', 'Marshall')
console.log(cache.get('name')) // Marshall
cache.remove('name')

暂存数据/高阶函数/Curry

const makeUrl = domain => path => `https://${domain}${path}`
const makeMsUrl = makeUrl('marshall.com')
const makdeGgUrl = makeUrl('google.com')
const url1 = makeMsUrl ('/about')
const url2 = makdeGgUrl ('/index')
console.log(url1) //"https://marshall.com/about"
console.log(url2) //"https://google.com/index"

练习题

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

for(var i=0; i {
  setTimeout(function(){
    console.log('clock:' + j )
  }, 0)
})(i)  
}

// 法三
for (var i = 0; i  {
    console.log('clock:' + i)
  })(i), 0)
}

以下代码输出什么

function Counter(n) {
  let num = 0
  function add(){
    num += n
    console.log(num)
  }
  return add
}
let counter1 = Counter(1)
counter1()
counter1()
// 1 2

let counter2 = Counter(2)
counter2()
counter2()
// 2 4

当点击li时输出什么?

  • 1
  • 2
  • 3
  • 4
let $arrLi = document.querySelectorAll('li') for(var i=0; i<$arrLi.length; i++) { $arrLi[i].onclick = function() { console.log(i) } } // 全是4 // 修改 // 法一 let $arrLi = document.querySelectorAll('li') for(let i=0; i {arrLi[i].onclick = () => console.log(i)})(i) } // 法三 let $arrLi = document.querySelectorAll('li') for(var i=0; i function(){ console.log(i) })(i) }

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

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

补全代码,把函数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)
function curry(fn) {
  return function curried(...args){
    if(args.length >= fn.length){
      console.log(fn.length)
      return fn(...args)
    }else{
      return function(...args2){
        return curried(...args.concat(args2))
      }
    }
  }
}
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。