【问题标题】:Difference between function level scope and block level scope函数级作用域和块级作用域的区别
【发布时间】:2014-02-14 06:29:48
【问题描述】:

我已经在JavaScript 编程了几个月,主要使用jQuery。我了解 闭包 并且已经使用过它们,但是,我仍然无法理解 在其他语言(例如 >C#。我一直在尝试自学,但在该主题上没有任何结果。有人可以用一些简单的例子来解释我吗?

【问题讨论】:

    标签: c# javascript function scope


    【解决方案1】:

    在 ES6(当前版本的 JavaScript)之前,JavaScript 只有函数级作用域。也就是如下:

    function foo() {
        console.log('before block: ' + bar);      // prints 'undefined'
        if(true) {
            var bar = 1;
            console.log('inside block: ' + bar);  // prints 1
        }
        console.log('outisde block: ' + bar);     // prints 1
    }
    

    完全等价于:

    function foo() {
        var bar;
        console.log('before block: ' + bar);      // prints 'undefined'
        if(true) {
            bar = 1;
            console.log('inside block: ' + bar);  // prints 1
        }
        console.log('outisde block: ' + bar);     // prints 1
    }
    

    (事实上,我刚刚展示的就是所谓的“提升”,这正是 JavaScript 所做的:所有变量 声明 都被提升到函数的顶部;赋值是离开他们所在的地方。)

    相比之下,像 C# 这样的语言具有块级范围。这会导致编译错误:

    public void Foo() {
        if(true) {
            var foo = 1;
            Console.WriteLine("inside block: " + foo);
        }
        Console.WriteLine("outside block: " + foo);  // WILL NOT COMPILE
    }
    

    但是你可以拥有这个:

    public void Foo() {
        var foo = 1;
        if(true) {
            foo = 2;
            Console.WriteLine("inside block: " + foo);  // prints 2
        }
        Console.WriteLine("outside block: " + foo);     // prints 2
    }
    

    【讨论】:

    • 我想我明白了。谢谢。
    • 很高兴它有帮助,Dimt。如果您认为这是最佳答案,请您将其标记为已接受吗?
    • 所以澄清一下,在 JS 中,如果在内部函数中声明了一个变量,则封闭函数可以访问该变量。在 C# 中这是不可能的。托管概念解释了我的误解。谢谢分配。
    • @EthanBrown 您误读了 OP 的注释 - 在 内部函数 中声明的变量无法被外部范围访问。
    • 说得对,Alnitak,很好。 Dimt,您所说的(“在 JS 中,如果一个变量在内部函数中被删除,则封闭函数可以访问该变量”)不是真的;函数内任何地方的变量声明都会屏蔽在外部作用域中声明的同名变量。
    【解决方案2】:
    function scopeTest() {
    
    /* consider this simple for loop
        to be the "block" that we were
        talking about earlier
    */
    for (var i = 0; i <= 5; i++)
    {
      var inFor = i; 
    }
    
    alert(inFor);  // what happens here?
    
    }
    
    
    // call the function defined above
    scopeTest( );
    

    在上面的代码中,我们有一个名为 inFor 的变量,它在 for 循环中声明。然后我们尝试在 alert 语句的 for 循环之外访问 inFor 变量。

    如果上面的代码没有提醒任何东西,那么我们知道这是因为 Javascript 使用了块作用域。在块范围语言中,变量 inFor 在 for 循环之外将不可见。这意味着如果 Javascript 是块范围语言,则调用“alert(inFor);”将无法识别 inFor 变量,并且不会向警告框输出任何内容。

    但是,上面的代码实际上输出了一个“5”,这意味着 inFor 变量确实存在于 for 循环之外,这一定意味着 Javascript 没有块范围。这就是我们的答案 - Javascript 没有块作用域。

    function scopeTest() {
    
    var x = 2;
    
    //this is always true:
    if(x == 2)
    {
      var y = 15;
      for (var i = 0; i <= 5; i++)
      {
        var inFor = i; 
      }
    } 
    
      console.log(y); // y is defined, prints 15   
      console.log(i);  // i is defined, prints 6
      console.log(inFor);  // inFor is defined, prints 5
    
    }
    

    您可以在上面的代码中看到变量 y、i 和 inFor 是在 if 语句或 for 循环中声明的。但是,即使这些变量是在这些单独的“块”内声明的,它们仍然对函数的其余部分可见。这是因为所有这些变量都在一个函数中声明——这就是函数作用域的全部意义所在。

    块范围与函数范围

    那么,如果 Javascript 不使用块作用域,那么它使用什么样的作用域呢?

    好吧,Javascript 使用了一种叫做函数作用域的东西。

    基本上,函数作用域和块作用域之间的区别在于,在使用函数作用域的语言中,函数内声明的任何变量在同一函数内的任何位置都是可见的。但是对于块作用域,变量的可见性仅限于由花括号括起来的任何给定块(无论是 if 语句、where/for 循环等)。

    http://www.programmerinterview.com/index.php/javascript/javascript-block-scope/ http://www.programmerinterview.com/index.php/javascript/javascript-function-scope/

        {
         here you can't access both a and b
         var a=1
         here you can access only a
            {
            here you can access only a
            var b=3
            here you can access both a and b
            {
            here you can access both a and b
            }
            here too you can access both a and b
            }
            here you can access only a
            }
           here you can't access both a and b
    

    【讨论】:

    • 因此,在块级范围内,For 循环中的迭代变量在外部块中不可访问,而在函数级范围内,它在外部函数中可见。对吗?
    • 不,请参阅 {} 这是变量的边界,因此您无法访问此边界之外的任何变量...注意...在 {} 内部此边界包含变量声明.. .
    • 看我更新的答案...希望你现在能理解
    • 我将尝试这些示例进行练习,这应该对我有所帮助。谢谢。
    【解决方案3】:

    继续@Ethan Brown 的回答,如果我们使用 let 或 const 而不是 var,我们会得到“referenceError”,因为 letconst 是块作用域的。

    function foo() {
        console.log('before block: ' + bar);      // ReferenceError: bar is not defined
        if (true) {
            let bar = 1;                          // bar is not let and not var
            console.log('inside block: ' + bar);  // prints 1
        }
        console.log('outisde block: ' + bar);     // ReferenceError: bar is not defined
    }
    

    只是想让答案完整。

    【讨论】:

      猜你喜欢
      • 2013-04-17
      • 1970-01-01
      • 1970-01-01
      • 2017-12-08
      • 2015-08-22
      • 2011-05-09
      • 2014-03-20
      • 2015-12-13
      • 2012-05-02
      相关资源
      最近更新 更多