这个 JavaScript 闭包是如何工作的?
这是一些 JavaScript:
linkElem.click(function () {
var data = linkElem.data();
alert(''+data.mls + ' ' + data.id);
});
它可以工作。
linkElem
是我在函数内的循环中创建的局部变量。我使用 jQuery 的 .data()
为其分配一些数据。如果我没有调用 .click()
,linkElem
将在循环期间重新分配,然后在函数返回后回收。但是,我创建了一个引用 linkElem
的匿名函数。所以我不再确定发生了什么事。
我的猜测是,在循环期间创建的所有匿名函数和 linkElem 都被赋予某种 UID,并移至持久/全局范围。这是正确的吗?无偿的细节将不胜感激。
Here's some JavaScript:
linkElem.click(function () {
var data = linkElem.data();
alert(''+data.mls + ' ' + data.id);
});
It works.
linkElem
is a local variable that I create in a loop inside a function. I assign some data to it with jQuery's .data()
. If I did not call .click()
, linkElem
would be reassigned during the loop and then recycled after the function returns. However, I have created an anonymous function which references linkElem
. So I am no longer sure what is going on.
My guess is that all of the anonymous functions and linkElem
s created during the loop are given UIDs of some kind and moved to persistent/global scope. Is this correct? Gratuitous detail would be much appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,你的描述非常接近。 Javascript 函数调用的本地存储只是为本地变量分配的一块内存。如果您通过在被调用函数内部创建另一个函数来“捕获”这一点,那么存储将被保留,并且局部变量将继续它们的生命,而不会意识到给出的函数他们的诞生可能早已死去。
重要的是要记住,只有函数才会创建这样的存储——诸如大括号封闭的循环体之类的东西不是独立的存储区域。因此,一个常见的错误是在函数中声明变量并在循环中创建的多个函数中重复使用它。这本质上并不是错误的,但效果可能会令人惊讶:
如果你运行它,你会看到三个警报,全部显示“3”。为什么?因为它们都共享相同的“i”变量。您可以通过引入另一个函数层来避免这种情况:
“包装器”函数只是提供一个局部变量(参数“private_i”),可以将循环变量“i”复制到其中。
Yes, your description is pretty close. The local storage for a Javascript function call is just a block of memory allocated for local variables. If you "capture" that by creating another function inside a called function, then the storage is retained and the local variables carry on with their lives, unaware that the function that gave them birth might be long dead.
It's important to keep in mind that only functions create such storage — things like brace-enclosed loop bodies are not separate storage areas. Thus a common error is to declare a variable in a function and re-use it among several functions created in a loop. That's not inherently wrong, but the effect can be surprising:
If you run that, you'll see three alerts that all say "3". Why? Because they all share the same "i" variable. You can avoid that by introducing another function layer:
The "wrapper" function is just there to provide a local variable (the parameter "private_i") whereto the loop variable "i" can be copied.
它仍然会被重新分配,除非您将它包装在另一个级别的范围中(注意:另一个函数)。
请考虑以下情况:
在本例中,所有这些链接在单击时都会发出警报
10
,因为j
超出了范围并且正在更新。如果您以相同的方式创建
linkElem
,您可能只会获得循环中lastlinkElem
的结果。这是一个更好的方法:
It still gets reassigned, unless you are wrapping it in another level of scope (NB: another function).
Consider the following:
In this case, all of those links would alert
10
when clicked, becausej
is outside of the scope and is being updated.If you're creating
linkElem
in the same way, you are likely to only get the result of the lastlinkElem
in the loop.This is a better way:
请参阅此 JavaScript 闭包如何工作?
这可能有助于您理解闭包。
每当您在另一个函数中看到 function 关键字时,内部函数就可以访问外部函数中的变量。
这将始终提醒 16,因为
bar
可以访问被定义为foo
参数的x
,并且它还可以访问来自
。foo
的 tmp那是一个闭包。函数不必返回才能被称为闭包。 简单地访问直接词法范围之外的变量就会创建一个闭包。
上面的函数也会警告 16,因为
bar
仍然可以引用x
和tmp
,即使它不再直接位于作用域内。然而,由于
tmp
仍然挂在bar
的闭包内,因此它也在递增。每次调用bar
时它都会递增。闭包最简单的例子是这样的:
当调用 Javascript 函数时,会创建一个新的执行上下文。与函数参数和父对象一起,此执行上下文还接收在其外部声明的所有变量(在上面的示例中,包括“a”和“b”)。
可以通过返回闭包函数列表或将它们设置为全局变量来创建多个闭包函数。所有这些都将引用相同
x
和相同tmp
,它们不会制作自己的副本。[你]:很有趣,告诉我更多!
这里的数字
x
是一个字面数字。与 JavaScript 中的其他文字一样,当调用foo
时,数字x
会作为其参数复制到foo
中x
。另一方面,JavaScript 在处理对象时总是使用引用。如果你用一个对象调用
foo
,它返回的闭包将引用那个原始对象!正如预期的那样,每次调用
bar(10)
都会增加x.memb
。可能出乎意料的是,x
只是引用与age
变量相同的对象!多次调用bar
后,age.memb
将变为 2!此引用是 HTML 对象内存泄漏的基础。Please refer to this How do JavaScript closures work?
This may help you understanding closures.
Whenever you see the function keyword within another function, the inner function has access to variables in the outer function.
This will always alert 16, because
bar
can access thex
which was defined as an argument tofoo
, and it can also accesstmp
fromfoo
.That is a closure. A function doesn't have to return in order to be called a closure. Simply accessing variables outside of your immediate lexical scope creates a closure.
The above function will also alert 16, because
bar
can still refer tox
andtmp
, even though it is no longer directly inside the scope.However, since
tmp
is still hanging around insidebar
's closure, it is also being incremented. It will be incremented each time you callbar
.The simplest example of a closure is this:
When a Javascript function is invoked, a new execution context is created. Together with the function arguments and the parent object, this execution context also receives all the variables declared outside of it (in the above example, both 'a' and 'b').
It is possible to create more than one closure function, either by returning a list of them or by setting them to global variables. All of these will refer to the same
x
and the sametmp
, they don't make their own copies.[you]: Fascinating, tell me more!
Here the number
x
is a literal number. As with other literals in JavaScript, whenfoo
is called, the numberx
is copied intofoo
as its argumentx
.On the other hand, JavaScript always uses references when dealing with Objects. If say, you called
foo
with an Object, the closure it returns will reference that original Object!As expected, each call to
bar(10)
will incrementx.memb
. What might not be expected, is thatx
is simply referring to the same object as theage
variable! After a couple of calls tobar
,age.memb
will be 2! This referencing is the basis for memory leaks with HTML objects.