似乎在C,Java和Ruby(而不是Javascript)之类的语言中,为循环块的每次迭代创建一个新范围,并且为循环定义的局部变量实际上被制作为局部变量每一次都记录在这个新的范围内?
例如,在Ruby中:
p RUBY_VERSION
$foo = []
(1..5).each do |i|
$foo[i] = lambda { p i }
end
(1..5).each do |j|
$foo[j].call()
end
打印输出是:
[MacBook01:~] $ ruby scope.rb
"1.8.6"
1
2
3
4
5
[MacBook01:~] $
因此,看起来在创建新作用域时,还会在此新作用域中创建并记录i
的新本地副本,以便在稍后执行该函数时,“i “在这些范围链中分别为1,2,3,4,5。这是真的? (这听起来像一个沉重的操作)。
与
对比p RUBY_VERSION
$foo = []
i = 0
(1..5).each do |i|
$foo[i] = lambda { p i }
end
(1..5).each do |j|
$foo[j].call()
end
这次,i
在进入循环之前被定义,因此Ruby 1.8.6不会将此i
放入为循环块创建的新范围中,因此当{{1}在范围链中查找,它总是引用外部范围内的i
,并且每次都给出5:
i
我听说在Ruby 1.9中,[MacBook01:~] $ ruby scope2.rb
"1.8.6"
5
5
5
5
5
[MacBook01:~] $
将被视为为循环定义的局部,即使之前定义了i
?
创建新作用域的操作,每次通过循环创建i
的新本地副本似乎很重,因为如果我们不在以后调用函数似乎没有关系。因此,当函数不需要在以后调用时,解释器和C / Java编译器是否可以尝试对其进行优化,以便每次都没有i
的本地副本?
答案 0 :(得分:1)
这与此处讨论的主题类似:http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/。在某些编程语言中,当循环变量时,循环结构的主体绑定到一个递增的变量。在其他情况下,每次迭代循环都会实例化一个新的循环变量。
对于词法范围,请注意,在JavaScript中,函数是唯一形成范围的构造(if
,while
,for
等的大括号,等等。在C / C ++中,任何一对括号都构成一个范围。