在Javascript中,函数会启动一个新的作用域,但我们必须小心,必须调用该函数才能创建作用域,是这样吗?
在Javascript中,我有时过于沉浸在函数创建新作用域的想法中,有时我什至认为下面的匿名函数在定义并分配给onclick时会创建新作用域:
<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>
<script type="text/javascript">
for (i = 1; i <= 5; i++) {
document.getElementById('link' + i).onclick = function() { var x = i; alert(x); return false; }
}
</script>
但事实上,匿名函数将创建一个新的作用域,这是正确的,但仅当它被调用时,是这样吗?因此匿名函数内的x
不会被创建,也不会创建新的作用域。当函数稍后被调用时,有一个新的作用域,但是i
在外部作用域中,并且x
得到它的值,而且它仍然是6 。
下面的代码实际上会调用一个函数并创建一个新的作用域,这就是为什么 x
每次都会在全新的作用域中成为一个新的局部变量 x
,并且调用单击链接时的函数将在不同的范围内使用不同的x
。
<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>
<script type="text/javascript">
for (i = 1; i <= 5; i++) {
(function() {
var x = i;
document.getElementById('link' + i).onclick = function() { alert(x); return false; }
})(); // invoking it now!
}
</script>
如果我们去掉x
前面的var
,那么它是一个全局x
,所以没有局部变量x
> 是在新作用域中创建的,因此,单击链接会得到所有相同的数字,即全局 x
的值。
更新:问题是:我们在分析代码时必须小心,函数在仅仅定义和赋值时不会创建作用域。它必须被调用。是这样吗?
In Javascript, I am sometimes too immerged in the idea that a function creates a new scope, that sometimes I even think the following anonymous function will create a new scope when it is being defined and assigned to onclick:
<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>
<script type="text/javascript">
for (i = 1; i <= 5; i++) {
document.getElementById('link' + i).onclick = function() { var x = i; alert(x); return false; }
}
</script>
but in fact, the anonymous function will create a new scope, that's right, but ONLY when it is being invoked, is that so? So the x
inside the anonymous function is not created, no new scope is created. When the function was later invoked, there is a new scope alright, but the i
is in the outside scope, and the x
gets its value, and it is all 6 anyways.
The following code will actually invoke a function and create a new scope and that's why the x
is a new local variable x
in the brand new scope each time, and the invocation of the function when the link is clicked on will use the different x
in the different scopes.
<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>
<script type="text/javascript">
for (i = 1; i <= 5; i++) {
(function() {
var x = i;
document.getElementById('link' + i).onclick = function() { alert(x); return false; }
})(); // invoking it now!
}
</script>
If we take away the var
in front of x
, then it is a global x
and so no local variable x
is created in the new scope, and therefore, clicking on the links get all the same number, which is the value of the global x
.
Update: the question is: we have to be careful when we analyze code, that a function will not create a scope when it is merely defined and assigned. It has to invoked. Is that so?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你说得对,但你自己也很困惑。不要将函数视为只是“创建一个新范围”,而是要了解真正发生的情况。 JavaScript 通过查看作用域链来解释变量。如果变量不存在于函数的作用域中,则在闭包的情况下,它将上升到封闭级别的作用域。该部分发生在解释变量时。作用域本身是在函数创建时创建的,但您感到困惑的是当时作用域中没有“捕获”任何内容。它只是扩大了范围链。
这就是为什么在 javascript 编程中将闭包放入循环中是一个“陷阱”——如果您想在执行时捕获
i
的值,那么放入自动执行的匿名函数是正确的。函数声明。人们倾向于认为(特别是来自过程语言)外部作用域被冻结,所有当前值都传递到新的函数作用域中,但事实并非如此。You're right, but you're also confusing yourself. Rather than thinking of functions as just "making a new scope" understand what's really happening instead. Javascript interprets a variable by looking at a scope chain. If the variable is not present in the function's scope, it will go up to the enclosing level's scope in the case of a closure. That part happens at the time the variable is interpreted. The scope itself is created when the function is, but where you're getting confused is nothing is "captured" in the scope at that time. It's just augmenting a scope chain.
That's why putting closures in loops is such a "gotcha" in javascript programming--you are right to put in in an auto-executing anonymous function if you want to capture the value of
i
at the time of function declaration. People tend to think (especially coming from procedural languages) that the outer scope is frozen and all current values are passed into the new function scope, and that's not true.函数的作用域是在函数对象创建时设置的,例如示例:
在上面的示例中,该函数是在
with
块中,当前作用域正在被扩充,以将具有
foo
属性的对象引入作用域链。在第二个示例中,情况相同,
onclick
处理程序函数是在自动调用匿名函数内创建的,该函数本身创建了一个新的词法作用域。在每次循环迭代中自动调用该函数时,
i
的值将被捕获到x
变量的该范围内,然后onclick 处理函数是在该范围内创建的,并且它将能够解析它。
The Scope of a function is set when the function object is created, for example:
In the above example, the function is created inside the
with
block, there the current scope is being augmented, to introduce the object with thefoo
property to the scope chain.In your second example, happens the same, the
onclick
handler function is being created inside the auto-invoking anonymous function, which itself has created a new lexical scope.At the moment that function is auto-invoked on each loop iteration, the value of
i
is captured into that scope in thex
variable, then theonclick
handler function is created inside that scope, and it will be able to resolve it.我不明白你的问题,但我不认为这有什么奇怪或错误的。
在第一种情况下,形成一个闭包,当调用事件时,它创建自己的作用域并从其外部作用域中的 i 获取值,该值由于闭包而得以维护。但该代码已经被执行,所以 i = 6,因为循环很长时间结束,因此,x = 6。
在后一个示例中,它是同一件事,您正在创建一个闭包,当事件被调用时,它将获取x 来自其外部作用域,由闭包维护,但它已经执行,并且由于它立即在循环中运行,这次 x 等于函数运行时的 i(以创建闭包)。
I do not understand your question, but I do not see anything weird or wrong with that.
In the first case, a closure is formed, and when the event is invoked, it creates its own scope and fetches the value from i in its outer scope, maintained due to the closure. But that code has already been executed so i = 6 because the loop is long finished, and thus, x = 6.
In the latter example, its the same thing, you are creating a closure, and when the event gets invoked it will fetch x from its outer scope, maintained by the closure, but it already executed, and since it ran immediately in the loop, this time x is equal to the i at the time the function was ran (to create the closure).