在Javascript中,函数启动一个新的作用域,但我们必须小心,必须调用函数才能创建作用域,是吗?

在Javascript中,函数启动一个新的作用域,但我们必须小心,必须调用函数才能创建作用域,是吗?,javascript,scope,closures,Javascript,Scope,Closures,在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 li

在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
前面的
var
,那么它是一个全局
x
,因此在新范围内不会创建任何局部变量
x
,因此,单击链接会得到所有相同的数字,即全局
x
的值


更新:问题是:我们在分析代码时必须小心,如果函数仅仅是定义和分配的,它不会创建作用域。它必须被调用。是吗?

我不明白你的问题,但我看不出有什么奇怪或错误

在第一种情况下,将形成一个闭包,当调用事件时,它将创建自己的作用域并从其外部作用域中的i获取值,该值由闭包维护。但是该代码已经执行了,因此i=6,因为循环已经完成了很长时间,因此x=6


在后一个示例中,这是同一件事,您正在创建一个闭包,当事件被调用时,它将从其外部作用域中获取x,由闭包维护,但它已经执行,并且由于它在循环中立即运行,此时x等于运行函数时的i(创建闭包).

函数的范围在以下情况下设置,例如:

var fn;
// augment scope chain:
with ({foo: "bar"}) {
  fn = function () { // create function
    return foo;
  };
}​​
// restored scope chain
fn(); // "bar"
在上面的示例中,函数是在块内创建的,当前范围在块内被扩展,以将具有
foo
属性的对象引入范围链

在您的第二个示例中,发生了相同的情况,
onclick
handler函数正在自动调用匿名函数中创建,该函数本身已经创建了一个新的词法作用域


在每次循环迭代中自动调用该函数时,
i
的值被捕获到
x
变量中的该作用域中,然后在该作用域中创建
onclick
处理程序函数,它将能够解决该问题。

你是对的,但你也弄糊涂了。与其把函数看作是“创建一个新的范围”,不如理解真正发生的事情。Javascript通过查看作用域链来解释变量。如果变量不在函数的作用域中,则在闭包的情况下,它将上升到封闭级别的作用域。该部分在解释变量时发生。作用域本身是在函数启动时创建的,但您感到困惑的是,当时作用域中没有“捕获”任何内容。这只是扩大了一个范围链


这就是为什么在javascript编程中把闭包放在循环中是一个“陷阱”——如果您想在函数声明时捕获
i
的值,那么将闭包放在自动执行的匿名函数中是正确的。人们倾向于认为(特别是来自过程语言的)外部作用域被冻结,所有当前值都被传递到新的函数作用域中,但事实并非如此

我不确定问题到底是什么。但是你必须像这样将
i
传递到你的作用域
(函数(i){…})(i)
几天前有一个类似的问题:对于任何感兴趣的人,我创建了一个和一个来处理这个问题。啊哈,没有任何东西被冻结,只是保留了作用域链的一个副本,以便在调用函数时,再次使用作用域链。因此,在一个框中“关闭代码和上下文”——闭包。
var fn;
// augment scope chain:
with ({foo: "bar"}) {
  fn = function () { // create function
    return foo;
  };
}​​
// restored scope chain
fn(); // "bar"