我是trying我最难绕过JavaScript闭包 .
我通过返回一个内部函数得到它,它将有权访问其直接父级中定义的任何变量 .
这对我有用吗?也许我还没有完全了解它 . 大多数examples I have seen online都没有提供任何真实世界的代码,只是模糊的例子 .
有人能告诉我现实世界中使用的闭包吗?
比如这个吗?
var warnUser = function (msg) {
var calledCount = 0;
return function() {
calledCount++;
alert(msg + '\nYou have been warned ' + calledCount + ' times.');
};
};
var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();
20 回答
我用闭包来做这样的事情:
正如你在那里看到的那样,
a
现在是一个对象,方法publicfunction
(a.publicfunction()
)调用privatefunction
,它只存在于闭包内 . 您可以 NOT 直接调用privatefunction
(即a.privatefunction()
),只需publicfunction()
.它是一个最小的例子,但也许你可以看到它的用途?我们使用它来强制执行公共/私人方法 .
假设您要在网页上 count the number of times user clicked a button .
为此,您将在 onclick 事件按钮上触发一个函数来更新变量的计数
现在可能有很多方法,如:
1)您可以使用 global variable 和函数来增加 counter :
但是,陷阱是 any script on the page can change the counter, without calling updateClickCount() .
2)现在,您可能正在考虑在函数内声明变量:
但是,嘿!每次调用
updateClickCount()
函数时, counter is set to 1 again.3)想到 Nested functions ?
嵌套函数可以访问范围"above" .
在此示例中,内部函数
updateClickCount()
可以访问父函数countWrapper()
中的计数器变量如果您可以从外部到达
updateClickCount()
函数,并且您还需要找到一种方法来执行counter = 0
,而不是每次都执行counter = 0
,这可以解决相反的困境 .4) Closure to the rescue! (self-invoking function) :
自调用函数只运行一次 . 它将
counter
设置为零(0),并返回一个函数表达式 .这样
updateClickCount
成为一个功能 . "wonderful"部分是它可以访问父范围中的计数器 .这被称为 JavaScript closure . 它使函数具有“私有”变量成为可能 .
counter
受匿名函数范围的保护,只能使用add函数进行更改!More lively example on Closure:
你给出的例子是一个很好的例子 . 闭包是一种抽象机制,允许您非常干净地分离关注点 . 您的示例是从语义(错误报告API)中分离检测(计数调用)的情况 . 其他用途包括:
是的,这是有用关闭的一个很好的例子 . 对warnUser的调用在其作用域中创建
calledCount
变量,并返回一个存储在warnForTamper
变量中的匿名函数 . 因为仍然有一个使用calledCount变量的闭包,所以它不会退出,因此每次调用warnForTamper()
都会增加作用域变量并提醒值 .我在StackOverflow上看到的最常见的问题是有人想要“延迟”使用在每个循环中增加的变量,但因为变量是作用域的,所以每个对变量的引用都将在循环结束后产生,导致变量的结束状态:
这将导致每个警报显示相同的
i
值,该值在循环结束时增加 . 解决方案是创建一个新的闭包,一个单独的变量范围 . 这可以使用即时执行的匿名函数来完成,该函数接收变量并将其状态存储为参数:特别是在JavaScript(或任何ECMAScript)语言中,闭包在隐藏功能实现的同时仍然可以显示接口 .
例如,假设您正在编写一类日期实用程序方法,并且您希望允许用户按索引查找工作日名称,但您不希望它们能够修改您在引擎盖下使用的名称数组 .
请注意,
days
数组可以简单地存储为dateUtil
对象的属性,但随后它将对脚本的用户可见,他们甚至可以根据需要更改它,甚至不需要您的源代码 . 但是,由于它由匿名函数包含,它返回日期查找功能,因此只能通过查找功能访问它,因此它现在是防篡改的 .在Mozilla Developer Network上有Practical Closures的部分 .
我知道我在回答这个问题时已经很晚了,但它可能会帮助那些仍然在2018年寻找答案的人 .
Javascript闭包可用于在您的应用程序中实现 throttle 和 debounce 功能 .
Throttling :
节流放了一个限制为一个函数可以随时间调用的最大次数 . 如“每100毫秒最多执行一次此功能” .
代码:
Debouncing :
去抖对一个函数设置了一个限制,直到一段时间过去而没有调用它为止 . 正如“只有在没有被调用的情况下经过100毫秒才执行此函数” .
码:
正如您所看到的,闭包有助于实现两个漂亮的功能,每个Web应用程序都应该提供流畅的UI体验功能 .
我希望它会帮助某人 .
闭包的另一个常见用途是将方法中的
this
绑定到特定对象,允许在别处调用它(例如作为事件处理程序) .每当发生mousemove事件时,都会调用
watcher.follow(evt)
.闭包也是高阶函数的一个重要部分,允许通过参数化不同部分,将多个相似函数重写为单个高阶函数的非常常见的模式 . 作为一个抽象的例子,
变
其中A和B不是语法单元,而是源代码字符串(不是字符串文字) .
有关具体示例,请参阅“Streamlining my javascript with a function” .
在这里,我有一个问候,我想多次说 . 如果我创建一个闭包,我可以简单地调用该函数来记录问候语 . 如果我不创建闭包,我必须每次都传递我的名字 .
没有闭包(https://jsfiddle.net/lukeschlangen/pw61qrow/3/):
有一个闭包(https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/):
如果您对在面向对象意义上实例化类的概念感到满意(即创建该类的对象),那么您就很容易理解闭包 .
可以这样想:当您实例化两个Person对象时,您知道实例之间不共享类成员变量"Name";每个对象都有自己的'copy' . 类似地,当您创建闭包时,自由变量(上例中的'calledCount')绑定到函数的'instance' .
我认为你的概念上的飞跃受到一个事实的影响,因为warnUser函数返回的每个函数/闭包(除了:这是一个高阶函数)闭包用相同的初始值(0)绑定'calledCount',而通常在创建闭包时它是将不同的初始化器传递给高阶函数更有用,就像将不同的值传递给类的构造函数一样 .
因此,假设当'calledCount'达到某个值时,您希望结束用户的会话;您可能需要不同的值,具体取决于请求是来自本地网络还是来自大型恶意互联网(是的,这是一个人为的例子) . 要实现这一点,您可以将calledCount的不同初始值传递给warnUser(即-3或0?) .
文献中的部分问题是用于描述它们的命名法(“词汇范围”,“自由变量”) . 不要让它欺骗你,封闭比看起来更简单......初步看法;-)
在这里,我有一个简单的闭包概念示例,我们可以在我们的电子商务网站或许多其他网站中使用它 . 我正在添加我的jsfiddle链接与示例 . 它包含3个项目的小产品列表和一个购物车柜台 .
Jsfiddle
我前段时间写了一篇关于如何使用闭包来简化事件处理代码的文章 . 它将ASP.NET事件处理与客户端jQuery进行了比较 .
http://www.hackification.com/2009/02/20/closures-simplify-event-handling-code/
我喜欢Mozilla的功能工厂example .
JavaScript模块模式使用闭包 . 它漂亮的模式允许你拥有类似“公共”和“私人”变种的东西 .
Use of Closures :
闭包是JavaScript最强大的功能之一 . JavaScript允许嵌套函数并授予内部函数对外部函数内定义的所有变量和函数(以及外部函数可以访问的所有其他变量和函数)的完全访问权限 . 但是,外部函数无法访问内部函数内定义的变量和函数 . 这为内部函数的变量提供了一种安全性 . 此外,由于内部函数可以访问外部函数的范围,因此如果内部函数设法超出外部函数的寿命,则外部函数中定义的变量和函数将比外部函数本身更长寿命 . 当内部函数以某种方式可用于外部函数之外的任何作用域时,将创建闭包 .
示例:
在上面的代码中,外部函数的name变量可以被内部函数访问,除了通过内部函数之外没有其他方法可以访问内部变量 . 内部函数的内部变量充当内部函数的安全存储 . 它们为内部函数提供了"persistent"但又安全的数据 . 甚至不必将功能分配给a变量,或者有一个名字 . 阅读here了解详情
参考:Practical usage of closures
实际上,闭包可以创建优雅的设计,允许自定义各种计算,延迟调用,回调,创建封装范围等 .
数组的排序方法示例,它接受排序条件函数作为参数:
将函数映射为数组的map方法,该函数根据函数参数的条件映射新数组:
通常使用功能参数来实现搜索功能是很方便的,这些参数定义了几乎无限的搜索条件:
另外,我们可能会注意应用函数,例如,一个将函数应用于元素数组的forEach方法:
函数应用于参数(对于参数列表 - 在apply中,在定义的参数中 - 在调用中):
延期电话:
回调函数:
为隐藏辅助对象而创建封装范围:
Fiddle
闭包是创建generators的有用方法,按需递增的序列:
差异总结如下:
References
这个主题帮助我更好地理解了闭包的工作原理 . 我已经做了一些自己的实验,并提出了这个相当简单的代码,可以帮助其他人看到如何以实用的方式使用闭包,以及如何在不同的级别使用闭包来维护类似于静态的变量/或全局变量,没有被覆盖或与全局变量混淆的风险 . 它的作用是跟踪每个按钮和全局级别的本地级别的按钮点击次数,计算每个按钮点击次数,从而为单个数字做出贡献 . 注意我没有使用任何全局变量来执行此操作,这是练习的重点 - 具有可应用于任何按钮的处理程序,该按钮也有助于全局 .
请专家,如果我在这里犯了任何不良行为,请告诉我!我自己还在学习这些东西 .
在给定的示例中,封闭变量'counter'的值受到保护,只能使用给定的函数(递增,递减)进行更改 . 因为它处于封闭状态,