美文网首页JavaScript
词法作用域 VS 动态作用域

词法作用域 VS 动态作用域

作者: 康斌 | 来源:发表于2016-10-12 08:54 被阅读1989次
    Javascript的词法作用域

    作用域是个语言无关的概念,你要接触过Lisp或者Scheme等语言,应该对这个概念会非常熟悉。我在这篇文章会介绍词法作用域和动态作用域的基本知识,让你刚好对这个概念了解,此外,我们还会讨论下JavaScript的词法作用域。

    首先你得明白程序设计中作用域这个概念:通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域

    词法作用域,也叫静态作用域,它的作用域是指在词法分析阶段就确定了,不会改变。动态作用域是在运行时根据程序的流程信息来动态确定的,而不是在写代码时进行静态确定的。

    我们以下面这段Javascript代码来说明词法作用域和动态作用域,但是你要明白,阐述的概念是与Javascript无关的。

    var a = 2;
    
    function foo() {
      console.log(a); // 会输出2还是3?
    }
    
    function bar() {
      var a = 3;
      foo();
    }
    
    bar();
    

    如果是词法作用域,它会让 foo() 函数引用到全局作用域中的 a,因此会输出 2。我们说过,词法作用域是写代码的时候就静态确定下来的。Javascript中的作用域就是词法作用域(事实上大部分语言都是基于词法作用域的),所以这段代码在浏览器中运行的结果是输出 2

    Javascript作用域链

    而动态作用域并不关心函数和作用域是如何声明以及在何处声明的,只关心它们从何处调用。换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套。因此,如果Javascript具有动态作用域,理论上输出结果是 3

    为什么会这样?因为当 foo() 无法找到 a 的变量引用时,会顺着调用栈在调用 foo() 的地方查找 a ,而不是在嵌套的词法作用域链中向上查找。由于 foo() 是在 bar() 中调用的,引擎会检查 bar() 的作用域,并在其中找到值为 3 的变量 a

    你可能会觉得很奇怪,但这其实是因为你可能只写过基于词法作用域的代码(或者至少以词法作用域为基础进行了深入的思考),因此对动态作用域感到陌生。如果你只用基于动态作用域的语言写过代码,就会觉得这是很自然的,而词法作用域看上去才怪怪的。

    需要明确的是,Javascript并不具有动态作用域,它只有词法作用域,简单明了。但是,它的 eval()withthis机制某种程度上很像动态作用域,使用上要特别注意。

    主要区别:词法作用域是在写代码或者定义时确定的,而动态作用域是在运行时确定的(this也是!)。词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用

    参考资料


    1. 书籍:《你不知道的JavaScript:上卷》
    2. 百度百科词条:作用域
    3. cnblogs:《浅谈静态作用域和动态作用域

    相关文章

      网友评论

        本文标题:词法作用域 VS 动态作用域

        本文链接:https://www.haomeiwen.com/subject/pkpbyttx.html