闭包,MDN给的概念是:闭包是函数和声明该函数的词法环境的组合。
作为前端,对于新手小白来说,闭包似乎有些陌生。很多大神老手也总是把闭包这东西说的神乎其神,似乎是一个很高深晦涩的概念。事实上在我看来闭包并不难懂,甚至你完全没有必要强行的去“弄懂它”,当你遇到它并最终解决问题的时候,事实上你已经弄懂了闭包。忘掉这个该死的概念,放开手去敲代码吧。下面我通过一个实际开发中遇到的典型案例,去解释它。
由于js没有块级作用域,我们在给页面写JQ脚本的时候往往这样写:
(function($) { })(jQuery)
这样写其实就形成了一个闭包,通过参数把JQ对象传进一个匿名函数中,然后我们所有的代码就在这个匿名函数中写。这样写的好处是保护作用域:因为一个页面你会加载多个js文件,如果都在同一个作用域下面,当你声明一堆全局变量或方法中不小心有一两个同名,就GG了。
下面再说一个前端开发中非常常见的一个案例:
后端哥们往前台抛了一个data对象,一个json数组。具体格式如下:
var data = [ { id:1, question:"1、马克思主义的产生具有深刻的社会根源、阶级基础和思想渊源,其创始人马克思1818年5月5日出生在德国特利尔城的一个律师家庭,恩格斯1820年11月28日出生在德国巴门市的一个工厂主家庭,他们放弃了舒适安逸的生活,毅然选择了充满荆棘坎坷的革命道路,创立了科学社会主义,马克思、恩格斯之所以能够创立科学社会主义,主要是因为()。", question_options_arr:["A.德国是当时最为发达的资本主义国家","B.德国是当时最为发达的资本主义国家","C.德国是当时最为发达的资本主义国家","D.德国是当时最为发达的资本主义国家"], answer:"【答案】:C(社会历史条件和个人努力的相互作用)", Analysis:"【题目分析】:社会历史条件和个人努力的相互作用是马克思和恩格斯创立科学社会主义的主要原因,故答案选C" }, { id:2, question:"2、马克思主义的产生具有深刻的社会根源、阶级基础和思想渊源,其创始人马克思1818年5月5日出生在德国特利尔城的一个律师家庭,恩格斯1820年11月28日出生在德国巴门市的一个工厂主家庭,他们放弃了舒适安逸的生活,毅然选择了充满荆棘坎坷的革命道路,创立了科学社会主义,马克思、恩格斯之所以能够创立科学社会主义,主要是因为()。", question_options_arr:["A.德国是当时最为发达的资本主义国家","B.德国是当时最为发达的资本主义国家","C.德国是当时最为发达的资本主义国家","D.德国是当时最为发达的资本主义国家"], answer:"【答案】:C(社会历史条件和个人努力的相互作用)", Analysis:"【题目分析】:社会历史条件和个人努力的相互作用是马克思和恩格斯创立科学社会主义的主要原因,故答案选C" }, { id:3, question:"3、马克思主义的产生具有深刻的社会根源、阶级基础和思想渊源,其创始人马克思1818年5月5日出生在德国特利尔城的一个律师家庭,恩格斯1820年11月28日出生在德国巴门市的一个工厂主家庭,他们放弃了舒适安逸的生活,毅然选择了充满荆棘坎坷的革命道路,创立了科学社会主义,马克思、恩格斯之所以能够创立科学社会主义,主要是因为()。", question_options_arr:["A.德国是当时最为发达的资本主义国家","B.德国是当时最为发达的资本主义国家","C.德国是当时最为发达的资本主义国家","D.德国是当时最为发达的资本主义国家"], answer:"【答案】:C(社会历史条件和个人努力的相互作用)", Analysis:"【题目分析】:社会历史条件和个人努力的相互作用是马克思和恩格斯创立科学社会主义的主要原因,故答案选C" }, { id:4, question:"4、马克思主义的产生具有深刻的社会根源、阶级基础和思想渊源,其创始人马克思1818年5月5日出生在德国特利尔城的一个律师家庭,恩格斯1820年11月28日出生在德国巴门市的一个工厂主家庭,他们放弃了舒适安逸的生活,毅然选择了充满荆棘坎坷的革命道路,创立了科学社会主义,马克思、恩格斯之所以能够创立科学社会主义,主要是因为()。", question_options_arr:["A.德国是当时最为发达的资本主义国家","B.德国是当时最为发达的资本主义国家","C.德国是当时最为发达的资本主义国家","D.德国是当时最为发达的资本主义国家"], answer:"【答案】:C(社会历史条件和个人努力的相互作用)", Analysis:"【题目分析】:社会历史条件和个人努力的相互作用是马克思和恩格斯创立科学社会主义的主要原因,故答案选C" }, ]
现在我们需要根据这个data去生成html。
这里我们当然要去遍历这个json数组,注意看到其中的question_options_arr字段又是一个数组,这可能意味着你需要在遍历中再加一层遍历。so easy!说写就写:
我们以JQ插件的形式写一个渲染html的方法:
满心欢喜的我们写完之后一经测试,尴尬了。你会发现每一题的选项都被重复渲染了。
通过检查,你发现是因为外部的循环影响了内部的循环,你在想如果外部的循环变量不“干扰”内部就好了。
下面我们进行闭包改造:
我们让内部循环形成一个闭包,然后通过参数把外部循环的变量传递给内部。再测试,成功了。
总结:问自己几个问题:闭包有什么用处?为什么要使用闭包?
用处,为什么要用:显然易见:隔离作用域,当你需要一个互不影响的作用域时,闭包就产生了。我们不是为了使用闭包而使用。