JavaScript 中的闭包/回调函数有哪些用例?
我正在听 Crockford 关于 JavaScript 闭包的演讲,并且确信信息隐藏的好处,但我对何时使用回调函数没有明确的理解。
这基本上是一个真实的说法,无论有没有回调,一个人都可以完成相同的功能。
作为编写代码的人,在确定何时使用回调/闭包时,我应该牢记哪些启发或提示?
我并不是在寻找笼统的声明“闭包使代码更安全”,而是在寻找回调何时是正确想法的实际示例或经验规则列表。
克罗克福德的介绍: http://www.yuiblog.com/blog/2010/ 04/08/video-crockonjs-5/
I was listening to Crockford's talk on JavaScript closures and am convinced of the benefit of information hiding, but I do not have a firm understanding of when to use callback functions.
It is mostly a true statement that a person could accomplish the same functionality with or without callbacks.
As someone who is writing code, what heuristics or cues should I keep in mind when determining when to use callbacks/closures?
I am not looking for the blanket statement 'Closures make more secure code', rather a list of practical examples or rules of thumb for when callbacks are the right idea.
Crockford's Presentation:
http://www.yuiblog.com/blog/2010/04/08/video-crockonjs-5/
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先:
回调也可以是闭包,但并非总是如此。
这是一个回调:
闭包:
闭包的一种常见用法是提供信息隐藏,这有助于为语言带来某种封装。查看模块模式以了解其实际情况。
另一个常见用法是将事件处理程序绑定到元素时。例如,
那是行不通的。单击该元素时,变量
i
为99
。为了使其正常工作,我们可以使用闭包来捕获i
的值:Firstly:
Callbacks can also be closures but are not always.
This is a callback:
A closure:
One common usage of closures is to provide information-hiding, which is helpful in bringing some kind of encapsulation to the language. Have a look at the module pattern to see this in action.
Another common usage is when the binding event handlers to elements. E.g.
That wouldn't work. By the time the element is clicked, the variable
i
is99
. To make this work properly we could use a closure to capture the value ofi
:假设您需要一个函数,可以用来返回唯一的“id”值,以便在创建新的 DOM 元素时使用。现在,在 Java 之类的东西中,您可以创建一个具有内部私有计数器的类,然后使用一个将计数器附加到某个前缀字符串的方法。好吧,在 Javascript 中:
现在变量“getId”绑定到一个由另一个函数创建的函数,并且创建的方式使得它有一个在调用之间使用的持久变量。同样,如果我想要一系列“getId”函数(例如,我可能添加的每种 DOM 元素都有一个函数),我可以这样做:
现在我可以调用
getId.div()
获取新的新“id”值。该函数是通过调用一个函数创建的,该函数提供存储在闭包中的两个值:前缀字符串(作为参数传入)和计数器(在闭包范围)。
一旦你习惯了它,该设施是如此灵活和有用,以至于你在搬回没有它的环境时会感到痛苦。
哦,如果您尝试一下,这里有一个提示可以帮助您远离 StackOverflow:这是一个一直弹出的问题:
这里有什么问题?那么,该函数引用的“i”变量是该循环运行范围内的“i”。您会注意到,该变量通过循环递增(呃,对吧?)。好吧,创建并分配为事件处理程序的每一个小函数都将在闭包作用域中共享同一个变量“i”。哎呀!解决方案是这样做:
我们将外部“i”的副本复制到其自己的闭包范围中,因此现在每个事件处理程序都有自己的!
总结一下:一旦你习惯了利用闭包的技术,所有时间都会出现。这并不是一张进入无错误编程新仙境的免费门票;它只是一张免费的门票。别误会我的意思。然而,它是一个非常有用且灵活的范例。
Let's say you want a function that you can use to return a unique "id" value to use when you create new DOM elements. Now, in something like Java, you could create a class with an internal private counter, and then have a method that appends the counter to some prefix string. Well, in Javascript:
Now the variable "getId" is bound to a function that's created by another function, and created in such a way that it has a persistent variable to use between invocations. Similarly, if I wanted to have a family of "getId" functions (say, one for each type of DOM element I might add), I could do this:
Now I can call
getId.div()
to get a new "id" value for a new<div>
. The function was created by calling a function that provides two values stashed away in a closure: the prefix string (passed in as an argument) and the counter (avar
declared in the closure scope).Once you get used to it, the facility is so flexible and useful that you'll feel pain at moving back to an environment without it.
Oh, and here's a tip to help keep you off StackOverflow should you try this out: it's an issue that pops up all the time:
What's the problem here? Well, that "i" variable that's referenced by that function is the "i" from the scope in which that loop runs. That variable, you'll note, gets incremented through the loop (duhh, right?). Well, every single one of those little functions created and assigned as event handlers will share that same, single variable "i" in the closure scope. Oops! The solution is to do something like this:
We make a copy of the outer "i" into a closure scope of its own, so now each event handler has its own!
To summarize: the technique of leveraging closures comes up all the freaking time once you get used to it. It's not a free ticket into a new wonderland of error-free programming; don't get me wrong. It is, however, a very useful and flexible paradigm.
Mozilla 的这篇文章可能会回答为什么使用闭包以及何时使用
, 查看这组示例(尤其是“闭包可以做什么?”部分)有以下示例):
setTimeout
我感觉这可以追溯到Crockford,但闭包的经典用途是模拟私有实例或静态变量(JavaScript 缺乏)
This writeup from Mozilla may answer why use closures and when
Also, see this set of examples (especially "What can be done with Closures?" section that has the following examples):
setTimeout
with Function ReferencesI have a feeling that this can be traced to Crockford, but the classic use of closures is to emulate private instance or static variables (which JavaScript lacks)