66

我在 Javascript 中阅读范围链,但它对我没有任何意义,谁能告诉我什么是范围链以及它如何与图形一起工作,甚至是白痴也能理解的东西。我用谷歌搜索了它,但我没有找到可以理解的东西:(

4

6 回答 6

70

要了解作用域链,您必须了解闭包的工作原理。

当您嵌套函数时会形成一个闭包,即使在其父函数已经执行之后,内部函数也可以引用其外部封闭函数中存在的变量。

JavaScript 通过向上遍历作用域链,从本地移动到全局来解析特定上下文中的标识符。

考虑这个包含三个嵌套函数的示例:

var currentScope = 0; // global scope
(function () {
  var currentScope = 1, one = 'scope1';
  alert(currentScope);
  (function () {
    var currentScope = 2, two = 'scope2';
    alert(currentScope);
    (function () {
      var currentScope = 3, three = 'scope3';
      alert(currentScope);
      alert(one + two + three); // climb up the scope chain to get one and two
    }());
  }());
}());

推荐阅读:

于 2009-09-27T19:15:44.390 回答
20

ECMAScript(JS 所基于的核心语言)中的任何函数调用都会产生一个单独的执行上下文,它们彼此单独运行。在每个执行上下文中,this指的是有问题的对象,默认为函数所附加的任何内容。

function foo() {
    alert(this===window)
}

会警告 true,因为窗口是拥有 'foo' 方法的对象。函数中定义的任何变量都可以通过该函数的唯一作用域链环境访问。

function world() {
    var name = 'global';
    alert(name)
}

显然会提醒“全球”。

function world() {
    var name = 'global';
    (function() {
        var name = 'country';
        alert(name)
    })();
    alert(name)
}

在最新示例中,当调用第一个警报时,Javascript 确定在内部函数的范围链中name定义了标识符,因此它不必查找范围链来获取它。

在第二次警报调用中,name也在相同的上下文中定义并警报“全局”;

function world() {
    var name = 'global';
    (function() { alert(name) })();
}

在此示例中,name标识符未在同一上下文中定义,因此它必须沿作用域链向上移动到定义名称的外部函数,并警告全局。

参考:

于 2009-09-27T18:55:20.960 回答
6

我知道这是一篇旧文章,但它仍然对开发人员有帮助。我想用一点不同的方式来做这件事,因为它对初学者来说更容易理解范围链。这是我修改后的代码版本:

var currentScope = 0; // global scope
function a () {
   var currentScope = 1, one = 'scope1';
   alert(currentScope);

  function b () {
      var currentScope = 2, two = 'scope2';
      alert(currentScope);

      function c () {
         var currentScope = 3, three = 'scope3';
         alert(currentScope);
  alert(one + two + three); // climb up the scope chain to get one and two
     }
     c();
  }
  b();
}
a();
于 2016-03-05T21:31:04.193 回答
5

这是关于关闭。您可以在内部范围内使用范围外的变量:

function get_inner_scope () {
    var outer = 'Outer variable value';
    return function () {
        alert(outer);
    }
}
f = get_inner_scope();
f(); // alerts Outer variable value

通过第一个 google 的链接获取更多关于其他示例的详细信息:http: //blogs.msdn.com/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx

于 2009-09-27T18:44:16.543 回答
4

Javascript中的范围链用外行术语解释

亚历克斯是个快乐的人,在美好的一天,他拿着月薪走在路上被抢劫了。

后来他意识到明天是支付女儿 1000 美元学费的最后一天。
他跑回家,找到了 400 美元的积蓄,担心剩下的(600 美元)。瞬间闪过的念头,是向父亲马修借一些。
可怜的木匠马修(Mathew)身无分文,以 300 美元的价格卖掉了他继承的手镯,并借给了他的儿子亚历克斯。
亚历克斯在社会上有很好的声誉,立即从当地一家银行拿到了剩余的300美元,并按时支付了女儿的学费。

回到 Javascript 中的作用域链:
Alex-javascript 中的函数
Mathew-立即函数,Alex 嵌套在
其中。Mathews parents-立即函数 Mathew 嵌套在其中。Bank-
全局变量。

function Bank() {
    loan=300;
    Mathew();

    function Mathew() {
        mathew=300;
        Alex();

        function Alex() {
            savings:400;
            alert('I need some money');
        }

    }

}

Bank();

此时 Alex 的作用域链如下所示:[savings:400]+[mathew:300]+[loan:300];

于 2016-07-07T10:26:36.707 回答
3

概括:

作用域链用于解析 javascript 中变量名的值。如果没有范围链,如果在不同的范围内定义了多个,Javascript 引擎将不知道为某个变量名称选择哪个值。javascript中的作用域链是词法定义的,这意味着我们可以通过查看代码来了解作用域链是什么。

作用域链的顶部是全局作用域,它是window浏览器中的对象(globalin NodeJS)。除了全局范围之外,函数还有自己的变量范围。范围链可以通过查看函数的定义位置来确定。

解析变量时,内部函数首先查看自己的作用域。如果在自己的作用域中找不到变量,它将爬上作用域链并在定义函数的环境中查找变量名称。这看起来像这样:

范围链 javascript

因此,在我们的图像示例中,当innerFoo使用变量时bar,它首先尝试在 innerFoo 的范围内(函数体中的代码)找到它。然后,当它在这里找不到它时,它会爬上作用域链foo. 其中foo也没有名为 的变量bar。因此,它将爬上作用域链,现在查看全局作用域。在全局范围内是一个名为 bar 的变量,其值为 10,bar将被解析为该变量。

例子:

let foo = 1;
let bar = 1;


function test (bar) {
   
   return function innerTestFunc () {
      let foo = 10;
      
      console.log(foo, bar);
    }
  
}

const innerTestFunc1 = test(5);
const innerTestFunc2 = test(20);


innerTestFunc1();  // logs 10, 5

innerTestFunc2();  // logs 10, 20

在上面的示例中,我们有一个返回函数的函数。我们首先将此函数存储在变量innerTestFunc1innerTestFunc2中。这将创建一个闭包,它基本上是外部环境范围链的快照。

然后,当执行函数时,函数需要变量foo和的值bar。foo 的值可以在 the 的级别上解析,innerTestFunc并且两者都是 10。10 已在 中找到innerFoo,因此无需爬上 foo 的作用域链。

bar变量的情况下,函数无法在innerFoo. 因此,它将爬上作用域链。它首先遇到bar函数中的变量test,因此它将值解析bar为测试函数中的任何值(在我们的示例中为 5、20)。

于 2018-09-02T08:18:46.673 回答