写代码啦

JS 中的闭包是什么?

ta 的热文

JS 中的闭包是什么?

大名鼎鼎的闭包!这一题终于来了,面试必问。 请用自己的话简述 什么是「闭包」。 「闭包」的作用是什么。 首先来简述什么是闭包 https://ooo.0o0.ooo/2017/06/19/594782b5671f0.png 假设上面三行代码在一个立即执行函数中(为简明起见,我就不写立即执行函数了,影响读者理解)。 评论里没看完就说我写得有问题的,请看清楚哦: 上面三行代码在一个立即执行函数中。 三行代码中,有一个局部变量 local,有一个函数 foo,foo 里面可以访问到 local 变量。 好了这就是一个闭包: 「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。 就这么简单。 有的同学就疑惑了,闭包这么简单么? 「我听说闭包是需要函数套函数,然后 return 一个函数的呀!」 比如这样: ``` function foo(){ var local = 1 function bar(){ local++ return local } return bar } var func = foo() func() ``` 这里面确实有闭包,local 变量和 bar 函数就组成了一个闭包(Closure)。 为什么要函数套函数呢? 是因为需要局部变量,所以才把 local 放在一个函数里,如果不把 local 放在一个函数里,local 就是一个全局变量了,达不到使用闭包的目的——隐藏变量(等会会讲)。 这也是为什么我上面要说「运行在一个立即执行函数中」。 有些人看到「闭包」这个名字,就一定觉得要用什么包起来才行。其实这是翻译问题,闭包的原文是 Closure,跟「包」没有任何关系。 所以函数套函数只是为了造出一个局部变量,跟闭包无关。 为什么要 return bar 呢? 因为如果不 return,你就无法使用这个闭包。把 return bar 改成 window.bar = bar 也是一样的,只要让外面可以访问到这个 bar 函数就行了。 所以 return bar 只是为了 bar 能被使用,也跟闭包无关。 闭包的作用 闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」。 假设我们在做一个游戏,在写其中关于「还剩几条命」的代码。 如果不用闭包,你可以直接用一个全局变量: window.lives = 30 // 还有三十条命 这样看起来很不妥。万一不小心把这个值改成 -1 了怎么办。所以我们不能让别人「直接访问」这个变量。怎么办呢? 用局部变量。 但是用局部变量别人又访问不到,怎么办呢? 暴露一个访问器(函数),让别人可以「间接访问」。 代码如下: ``` !function(){ var lives = 50 window.奖励一条命 = function(){ lives += 1 } window.死一条命 = function(){ lives -= 1 } }() ``` 简明起见,我用了中文 :) 那么在其他的 JS 文件,就可以使用 window.奖励一条命() 来涨命,使用 window.死一条命() 来让角色掉一条命。 看到闭包在哪了吗? https://ooo.0o0.ooo/2017/06/19/594783a688fae.png 闭包到底是什么? https://ooo.0o0.ooo/2017/06/19/594783d960b63.png 五年前,我也被这个问题困扰,于是去搜了 stackoverflow 并总结下来。你在百度搜闭包,那篇《JavaScript闭包——懂不懂由你,反正我是懂了》就是我写的。当时我还是新手,一直不理解为什么大家口中的闭包这么模糊、这么琢磨不定呢。 我们重新来审视一下闭包的代码: https://ooo.0o0.ooo/2017/06/19/594782b5671f0.png 第一句是变量声明,第二句是函数声明,第三句是 console.log。 每一句我都学过,为什么合起来我就看不出来是闭包? 我告诉你答案,你根本不需要知道闭包这个概念,一样可以使用闭包! 闭包是 JS 函数作用域的副产品。 换句话说,正是由于 JS 的函数内部可以使用函数外部的变量,所以这段代码正好符合了闭包的定义。而不是 JS 故意要使用闭包。 很多编程语言也支持闭包,另外有一些语言则不支持闭包。 只要你懂了 JS 的作用域,你自然而然就懂了闭包,即使你不知道那就是闭包! 所谓闭包的作用 如果我们在写代码时,根本就不知道闭包,只是按照自己的意图写,最后,发现满足了闭包的定义。 那么请问,这算是闭包的作用吗? 这个问题,留给你思考。 关于闭包的谣言 闭包会造成内存泄露? 错。 说这话的人根本不知道什么是内存泄露。内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。 闭包里面的变量明明就是我们需要的变量(lives),凭什么说是内存泄露? 这个谣言是如何来的? 因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。 这是 IE 的问题,不是闭包的问题。参见司徒正美的这篇文章 (http://link.zhihu.com/?target=http%3A//www.cnblogs.com/rubylouvre/p/3345294.html)。 一个小经验 编程界崇尚以简洁优雅唯美,很多时候 如果你觉得一个概念很复杂,那么很可能是你理解错了。 完。 想学前端?进群 (http://qr.jirengu.com/api/taskUrl?tid=1)
 2189 ·  07月31日 15:36
blog

Callback(回调)是什么?

Callback 是什么? callback 是一种特殊的函数,这个函数被作为参数传给另一个函数去调用。这样的函数就是回调函数。 callback 拆开,就是 call back,在英语里面就是「回拨电话」的意思。 那我们就用打电话为例子来说明一下 callback: 「我打电话给某某」(I call somebody),那么「打电话」的人就是「我」。 「我」在电话里说:你办完某事后,回拨电话给「我」。 某某做完事后,就会「回拨电话给我」(calls back to me),那么「打电话」的人就是「某某」。 用编程来解释的话,是这样的: 「我调用一个函数 f」(I call a function),那么「调用函数」的人是「我」。代码是 f(c)。 「我」让这个函数 f 在执行完后,调用我传给它的另一个函数 c。 f 执行完的时候,就会「调用 c」,也叫做「回调 c」(call c back),调用 c 的人是 f。 好了,解释完了:callback 就是(传给另一个函数调用的)函数。 把括号里面的内容去掉,简化成:callback 就是一种函数。 Callback 很常见 $button.on('click', function(){}) click 后面的 function 就是一个回调,因为「我」没有调用过这个函数,是 jQuery 在用户点击 button 时调用的。 div.addEventListener('click', function(){}) click 后面的 function 也是一个回调,因为「我」没有调用过这个函数,是浏览器在用户点击 button 时调用的。 一般来说,只要参数是一个函数,那么这个函数就是回调。 Callback 有点反直觉 很多初学者不明白 callback 的用法,因为 callback 有一点「反直觉」。 比如说我们用代码做一件事情,分为两步:step1( ) 和 step2( )。 符合人类直觉的代码是: step1() step2() callback 的写法却是这样的: step1(step2) 为什么要这样写?或者说在什么情况下应该用这个「反直觉」的写法? 一般(注意我说了一般),在 step1 是一个异步任务的时候,就会使用 callback。 什么是异步任务呢?且听下回分解。 想学前端?进群 (http://qr.jirengu.com/api/taskUrl?tid=1)
 1578 ·  07月31日 14:55
blog

为什么不推荐 W3Schools

W3Schools 跟 W3C 组织没有关系 W3Schools 是由挪威的 Refsnes Data 创建的,我们可以将其定位一个「教程网站」,它提供了参考手册、代码样例和 Try it yourself 沙盒。 由于早期 W3C 和 MDN 的文档对新人极其不友好,所以 W3Schools 很快成本前端开发入门的首选教程。 W3Fools 对 W3Schools 的批评 权威性受到质疑 W3C 组织曾要求 W3Schools 在显著的地方注明「 W3School 与 W3C 没有任何关系」,但是 W3Schools 没有这样做。 2011 年一个独立的网站上线,那就是W3Fools.com (http://link.zhihu.com/?target=http%3A//W3Fools.com),当时它最主要的口号就是「 We believe W3Schools is harmful to the web. Web developers deserve better 」。 W3Fools 指出 W3Schools 的内容漏洞百出,而且没有给阅读者深入了解的参考,对所有内容浅尝辄止,不是一个教程该有的态度。 W3Schools 倒也虚心,在这几年里不断地修复着自己的错误,并且在页面下方添加了一段话: W3Schools is optimized for learning, testing, and training. Examples might be simplified to improve reading and basic understanding. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. W3Schools 是为学习、测验和练习而成立。为了方便阅读和理解,本站的例子都做了一些简化。我们在持续改进我们的教程、参考手册和实例代码,以尽量减少错误,如有疏漏,还望见谅。 作为一个不需要深入理解的学习者, W3Schools 确实不错。 更好的选择 W3Fools 认为比 W3Schools 更好的参考网站是 Mozilla Developer Network (http://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/) 和 Web Platform Docs (http://link.zhihu.com/?target=http%3A//www.webplatform.org/),内容权威,并提供了进一步深入了解的链接。 Web developers deserve it. 参考 What is the story behind www.w3fools.com? (http://link.zhihu.com/?target=http%3A//www.infragistics.com/community/blogs/devtoolsguy/archive/2016/01/29/what-is-the-story-behind-www-w3fools-com.aspx) P.S. 至于w3school 在线教程 (http://link.zhihu.com/?target=http%3A//www.w3school.com.cn/)中文版的 w3school(没有 s ),还不如 W3schools 。唯一的有点就是「翻译成了中文」。 想学前端?进群 (http://qr.jirengu.com/api/taskUrl?tid=1)
 1504 ·  07月31日 14:51
blog