闭包内的变量的继承是在定义闭包还是执行闭包函数时检查的?
下面比较了 c#、golang 、javascript 、php5 、python3 、ruby 的闭包或 lambda 。主要思路是写好闭包,再定义变量 y,其中闭包内用到 y 变量。
我的总结是:python3 、javascript 都是在执行时才检查闭包内变量,而 c#、golang 、php5 、ruby 都是在定义时已检查闭包内变量的。注意 golang 是编译型语言,c#是解释型语言(??)。
我是"hello world"水平,写错了轻拍,欢迎指正。php5 的闭包我不是很懂,照抄例子的,可能有错。
我本来是希望 ruby 的闭包可以像 python3 那样在执行闭包时再检查闭包内的变量的,查了一下其他语言才发现不统一的情况有点多。
以下是代码。
// c# 闭包 编译错误,在指定 f()时不存在 y
using System;
public class Test {
delegate int Func();
public static void Main() {
int x = 1;
Func f = () => (x+y);
int y = 2;
Console.WriteLine(f());
}
}
// golang 闭包,编译错误,在指定 f()时不存在 y
package main
import "fmt"
func main () {
var x int = 1
f := func() int { return (x+y)}
var y int = 2
result := f()
fmt.Println(result)
}
// javascript 闭包,找得到 y
var x = 1;
function f() {
function g() {
return (x+y);
}
return g;
}
var y = 2;
console.log(f()());
# php5 闭包,找不到$y
$x = 1;
$f = function() use ($x, $y) { return ($x + $y); };
$y = 2;
echo($f());
# python3 闭包 1,都能找到 y
x = 1
def f():
def g():
return (x+y)
return g()
y = 2
print(f())
# python3 闭包 2
x = 1
lam = lambda : (x+y)
y = 2
print(lam())
# ruby 闭包 1 都找不到 y
x = 1
pr = Proc.new do
(x+y)
end
y = 2
puts 'proc 定义完毕'
puts pr.call
# ruby 闭包 2
x = 1
lam = lambda { return (x+y) }
y = 2
puts lam.call
1
Zhuzhuchenyan 2020-03-27 19:41:10 +08:00
那具体说下 JS 为何能运行吧,var 在声明变量并赋值的时候,其实会做两个步骤,在词法作用域最上方声明,以及在该赋值的时候赋值,具体来说,以下代码和你贴出的代码等价:
var x; var y; x = 1; function f() { function g() { return (x+y); } return g; } y = 2; console.log(f()()); 所以代码在运行到 x+y 这一行时完全知道 y 存在于全局的词法作用域(也就是说可以在闭包封闭的词法作用域中被引用到) 这种编程方式一般不被推荐,配置 lint 规则后会给出 variable 'y' used before declaration (no-use-before-declare)的报错 |