在函数外部能够读取其他函数内部变量的函数。
通俗理解的闭包: 一个内部函数引用了外部函数的变量,外部函数形成了一个闭包.
闭包认识
初体验
例:在函数的外部实现函数内部变量的访问
function fun1(){ var n=999; function fn2(){ console.log(n); } return fn2; //fn2 就是一个闭包函数,因为他能够访问到fun1函数的作用域 } var r=fun1(); r();
原理
js中的变量,函数在执行的时候都会被加载到栈中,执行完毕在弹出,当使用闭包的时候,函数执行完成后,不会弹出,因为其他的地方还要加载其内部变量.
闭包的特点
1 使用不当会很容易造成内存泄露(内存中能存的东西越来越少,像是其他部分被泄露了一样)
2 设置私有变量(内部函数调用外部函数的局部变量,此时,这个局部变量就会变成内部函数的私有变量)
3 闭包的作用:充当一个摄像头,函数外部可以访问函数内部的变量,减少变量的声明,避免造成污染.
4 内存的占用比较大,浪费内存.
函数柯理化
是什么
只是一种闭包的应用
只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数。这个过程就叫做柯里化。
核心思想是把多参数传入的函数拆成单参数(或部分)函数,内部再返回调用下一个单参数(或部分)函数,依次处理剩余的参数
原理
柯里化的作用最直观的用法就是节省代码中共同参数的重复,比如一个函数有四个参数,其中前三个在多次调用中都是一样的,最后一个视情况不同,伪代码如下:
fun(a, b, c, 'hello') fun(a, b, c, 'world')
为了减少参数的重复,可以把函数curry化
cf = curry(fun, a, b, c) cf('hello') cf('world')
场景1: 参数的复用
验证密码是否符合要求
方法1:正常写法
function check(reg, str) { return reg.test(str) } // 验证密码 const res = check(/^\w{6,12}$/, 'asdhgfahsd') const res2 = check(/^\w{6,12}$/, 'sdfsdf')
方法2:利用闭包
function fn(reg) { return function inner(str) { return reg.test(str) } } const nameTest = fn(/^\w{5,11}$/) const r3 = nameTest('asd') console.log(r3); 上面的示例是一个正则的校验,正常来说直接调用check函数就可以了,但是如果我有很多地方都要校验是否有数字,其实就是需要将第一个参数reg进行复用,这样别的地方就能够直接调用hasNumber,hasLetter等函数,让参数能够复用,调用起来也更方便。
场景2: 提前返回
在JS DOM事件监听程序中,我们用addEventListener方法为元素添加事件处理程序,但是部分浏览器版本不支持此方法,我们会使用attachEvent方法来替代。
这时我们会写一个兼容各浏览器版本的代码:
平常写法:
/** * @description: * @param {object} element DOM元素对象 * @param {string} type 事件类型 * @param {Function} fn 事件处理函数 * @param {boolean} isCapture 是否捕获 * @return {void} */ function addEvent(element, type, fn, isCapture) { if (window.addEventListener) { element.addEventListener(type, fn, isCapture) } else if (window.attachEvent) { element.attachEvent("on" + type, fn) } }
柯理化的写法
// 也可以用立即执行函数将上述代码合并 const addEvent = (function curryingAddEvent() { if(window.addEventListener){ return function(element,type,fn,isCapture){ element.addEventListener(type,fn,isCapture); } }else if(window.attachEvent){ return function(element,type,fn){ element.attachEvent('on'+type,fn); } } })()
现在我们得到的addEvent是经过判断后得到的函数,以后调用就不用重复判断了。
这就是提前返回或者说提前确认,函数柯里化后可以提前处理部分任务,返回一个函数处理其他任务。