害,作为js三座大山中的一座泰山,闭包属实困扰了很多登山的同志,今天我也想来挑战挑战这座大山。但是云深不知处,只缘身在此山中,你可能觉得你还在山腰,却可能快接近山巅,你以为你到了山巅,却不知还在山脚,因此我这篇对于闭包讨论的文章,可能存在诸多偏颇,还请谅解,如有更好更精妙的意见,可在评论区中与我一起讨论。PS:我只是个小菜鸡。
既然是讨论闭包,那么我们就得先知道他的概念:闭包就是能够读取其他函数内部变量的函数。这是百度百科给出的定义,由此一句话属实难过,这啥呀这是,你玩不起,你小垃圾,抱歉,抖音中毒了,回归正题。
我认为闭包需要两个组成部分:[函数 + 变量];
该概念我是于一位大佬的这篇文章中看到的,觉得甚是精妙。
先看代码:
function fn1(){ var monkey='熏悟空'; function fn2(){ console.log(monkey) } return fn2; } var a=fn1(); a()
这就是一个最简单的闭包,请注意,我是说函数f2加上内部打印的monkey变量合起来是一个闭包,不是说这一个整体,也不是单纯说函数f2,因为根据概念,闭包能够读取其他函数内部的变量,如果你去掉了对于变量monkey的打印,那么也就失去了对于变量monkey的读取,那么这无法形成一个闭包。
那么上面这个闭包起到了什么作用呢?他让定义在全局作用域下的a读取到了函数f1内部的私有变量monkey,这就是闭包的一个特点。
那么经常有人说闭包和return共生,有闭包一定有return,其实不然,闭包与return无关,那么有人就会说了,你不return就无法访问到这个闭包。其实return只是暴露出这个闭包,让你能够访问而已。它和闭包无绝对关系,因为你也可以这么写:
function fn1() { var monkey = '熏悟空'; window.fn2 = function () { console.log(monkey) } } fn1(); fn2();
或者这么写:
var fn2; function fn1() { var monkey = '熏悟空'; fn2 = function () { monkey = '逼马吻'; console.log(monkey) } } fn1(); fn2();
这两种写法中函数f2加上内部访问的变量monkey依旧是一个闭包。
闭包有什么作用呢?闭包通常用来间接访问一个变量,或者说隐藏一个变量。
见代码:
function monkey() { var name = '石猴儿'; window.puti=function () { name = '熏悟空'; } } monkey(); puti();
就说天地生的一个石猴儿,想要换一个名字,好,大家都来了,这给斗战胜佛取名字多威风啊,结果这个性情刚烈的猴儿说猴可杀不可辱,你们这些凡夫俗子岂能给我取名字,我的名字只能由菩提老祖来取,好,最后菩提老祖说时候事多,赏了石猴三个脑瓜崩,给石猴儿取名熏悟空。
上面例子中石猴儿的名字是石猴儿的私有存在,其他人碰不得,不能碰,只能够由石猴儿认可的菩提老祖才能更改,由此菩提老祖加上对石猴儿名字的访问权就形成了一个闭包,只能通过他来间接访问石猴儿的名字。
为什么通常闭包都是函数嵌套函数呢,因为有函数的定义和作用决定:定义:访问函数内部的变量;作用:间接访问。如果不是函数嵌套函数,而是下面这种情况:
var name = '石猴儿'; function puti () { name = '熏悟空'; } puti();
这个时候的puti加上对name变量就不是一个闭包,因为name变量处于全局作用域下,谁都可以访问,没有达到通过puti间接访问的目的。所以闭包的出现通常都是函数套函数。