javascript函数内部范围

时间:2013-07-08 04:45:34

标签: javascript

请考虑以下代码:

function nepaliBuddha() {
    var a = 20;

    return function buddhaNepal() {
        console.log(a); 
    }
}

var closure = nepaliBuddha();

closure(); // logs 20
  1. 现在,当我们调用closure时,输出为20。这证明了内部范围属性([[scope]])已分配给定义它的内部函数,或者在声明时说明。如果未在声明中分配,则无法记录20,因为它被调用不同的背景

  2. 调用closure()函数上下文的作用域链是在函数调用时创建的,由当前上下文的激活对象或VO 和内部{{1}组成。这个函数的属性。

  3. 调用还会创建[[scope]]属性,这意味着内部范围属性是在声明时创建的,也不是在执行时创建的?

  4. 通常定义说[[scope]]属性是在运行时或函数调用时创建的,但这不是真的,因为[[scope]]属性已在声明中分配。

  5. 我认为[[scope]]属性在执行函数后可能会更新,是吗?请明确[[scope]]内部属性的定义。如何以及何时在申报时或执行时或两次创建。

2 个答案:

答案 0 :(得分:8)

哇,你不是彻底搞砸了。好吧,我会尽可能简单地解释闭包。

首先,我们将从范围开始。有两种类型的范围:

  1. 阻止范围
  2. 功能范围
  3. 块程序在程序中发生时立即开始。另一方面,函数作用域在调用函数之前不会开始。因此,对同一函数的多次调用会导致创建多个范围。

    JavaScript没有块范围。它只有功能范围。因此,要模拟块作用域,我们需要创建一个函数表达式并立即执行它。这个patttern被称为immediately invoked function expression (IIFE),它看起来像这样:

    (function () {
        // this is the JS equivalent of a block scope
    }());
    

    除了块范围和功能范围之外,还有另一种对范围进行分类的方法。因此我们也有:

    1. 词汇范围
    2. 动态范围
    3. 这种区别仅适用于函数范围,因为块范围始终是词法范围的。 JavaScript只有词法范围。

      要理解词法范围和动态范围之间的区别,我们需要了解自由变量和绑定变量之间的区别。

      1. 自由变量是一个在函数中使用但未在该函数中声明的变量。
      2. 在函数中声明的变量被称为绑定到该函数。
      3. 考虑以下计划:

        function add(x, y) {
            return x + y; // x and y are bound to add
        }
        

        在上面的程序中,变量xy绑定到函数add,因为它们是在add中声明的。

        另一方面,以下程序中的变量xy在函数add中是免费的,因为它们未在add内声明,但它们在add

        function add() {
            return x + y; // x and y are free within add
        }
        

        现在自由变量是个问题。它们需要映射到某个值,但是哪个值?这是词汇和动态范围的结果。我不会详细介绍,但你可以read about it on Wikipedia

        范围很像原型继承。当一个新的范围开始时,它继承自父范围,形成一系列范围,就像JavaScript中的原型链一样。

        词法范围和动态范围因新范围继承形式的父范围而不同。

        1. 在词法作用域中,新的函数作用域继承自定义该函数的作用域(即其词法环境)。
        2. 在动态作用域中,新的函数作用域继承自调用该函数的作用域(即调用作用域)。
        3. 由于JavaScript只有词法范围,我们不会为动态范围而烦恼。请考虑以下程序:

          var count = 0;
          
          function incrementCount() {
              return ++count;
          }
          
          (function () {
              var count = 100;
              alert(incrementCount()); // 1
          }());
          

          此处函数incrementCounter有一个自由变量 - count。由于JavaScript具有词汇范围count,因此将映射到全局变量count,而不是IIFE中声明的本地count。因此,incrementCount会返回1而非101

          现在,闭包仅适用于具有词法作用域的语言。请考虑以下程序:

          function getCounter() {
              var count = 0;
          
              return function () {
                  return ++count;
              };
          }
          
          var counter = getCounter();
          
          alert(counter()); // 1
          alert(counter()); // 2
          alert(counter()); // 3
          

          在上面的程序中,getCounter返回的函数是关于变量count的闭包,因为:

          1. 变量count在返回的函数中是免费的(即counter)。
          2. 该函数移出声明count的范围之外。
          3. 这两个条件都是函数被称为闭包所必需的。有关更多信息,请阅读以下答案:https://stackoverflow.com/a/12931785/783743

            现在要理解的重要一点是函数counter仍然会被称为闭包,即使它永远不会被调用。闭包只是一个关闭变量的函数(称为闭包的upvalue)。

            当我们调用getCounter时,我们创建一个新的范围(让我们调用这个范围A),每次我们调用getCounter返回的函数(即counter)我们创建了一个继承范围A的新范围。就这样。没有创建新的闭包。

答案 1 :(得分:1)

closure是一种特殊的对象,它结合了两个东西:一个函数,以及创建该函数的环境。该环境由关闭创建范围内的任何局部变量组成。

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

现在致电makeFunc()

var myFunc = makeFunc();
myFunc();

在这种情况下,myFunc是一个闭包,它包含{<1}}函数和闭包创建时存在的“Mozilla”字符串,{{3} }。

因此,我在调用displayNamescopevar myFunc = makeFunc();调用的结果)时创建的myFunc()现在是一个闭包。那么,转到第一行

  

makeFunc()是一种特殊的对象,它结合了两件事:   功能,以及创建该功能的环境。

现在考虑这些

closure

MDN

这意味着,function nepaliBuddha() { var a = 1; return function buddhaNepal() { a = a+1; console.log(a); } } var closure1 = nepaliBuddha(); // An individual scope var closure2 = nepaliBuddha(); // An individual scope closure1(); // 1 closure1(); // 2 closure2(); // 1 closure2(); // 2 closure2(); // 3 closure1()是封闭的,并且都有自己的个人范围/环境,一旦获得它们就可以访问自己的范围(在这种情况下,每次调用{{ 1}}您正在创建一个闭包并将其保存/保存到变量中。

范围定义了可用的函数,变量等区域。所以,当你在closure2()(外部函数)中定义/声明函数nepaliBuddha(内部函数)时,buddhaNepal(内部函数)刚刚与全局作用域分离,没有别的。它不能访问全局范围内的任何东西,但它有自己的范围,就是这样。 nepaliBuddha(外部函数)是buddhaNepal(内部函数)的边界,在这种情况下,nepaliBuddha外部函数的局部范围/环境是{{1}的全局范围。 (内部函数)。

在JavaScript中,这称为buddhaNepal,它定义了如何在嵌套函数中解析变量名称。词法范围的其他名称是静态范围或关闭。这意味着内部函数的范围包含父函数的范围。