V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
crella
V2EX  ›  程序员

闭包内的变量的继承是在定义闭包还是执行闭包函数时检查的?

  •  
  •   crella · 2020-03-27 17:37:43 +08:00 · 907 次点击
    这是一个创建于 1491 天前的主题,其中的信息可能已经有所发展或是发生改变。

    闭包内的变量的继承是在定义闭包还是执行闭包函数时检查的?

    下面比较了 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 条回复    2020-03-27 19:41:10 +08:00
    Zhuzhuchenyan
        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)的报错
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1945 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 16:21 · PVG 00:21 · LAX 09:21 · JFK 12:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.