典型的闭包是一个函数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
function Counter() { let num = 0 return function() { num++ console.log(num) } } let count1 = Counter() count1() //1 count1() //2 let count2 = Counter() count2() //1 count2() //2
换一种写法
const sum = a => b => a + b console.log(sum(3)(4))
更宽泛的场景是函数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()
function Counter() { let num = 0 function add(){ num ++ console.log(num) } setTimeout(add, 1000) } let counter = Counter()
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', '饥人谷') cache.get('name'); // '饥人谷' cache.remove('name')
const makeUrl = domain => path => `https://${domain}${path}` const makeJrgUrl = makeUrl('jirengu.com') const makdeXdmlUrl = makeUrl('xiedaimala.com') const url1 = makeJrgUrl ('/about') const url2 = makdeXdmlUrl ('/index')
for(var i=0; i<5; i++){ setTimeout(function(){ console.log('clock:' + i ) }, 0) }
function Counter(n) { let num = 0 function add(){ num += n console.log(num) } return add } let counter1 = Counter(1) counter1() counter1() let counter2 = Counter(2) counter2() counter2()
<ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul>
let $arrLi = document.querySelectorAll('li') for(var i=0; i<$arrLi.length; i++) { $arrLi[i].onclick = function() { console.log(i) } }
function sum(a, b, c) { return a + b + c }
function sum(a, b, c, d) { return a + b + c + d } function curry(fn) { //补全 } let newSum = curry(sum) newSum(1)(2)(3)(4)
//方法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) }
输出 1 2 2 4
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) }
function sum(a) { return function(b, c) { return a + b + c } } const sum = a => (b, c) => a + b + c
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)