美文网首页
你不知道的JS:作用域是什么?

你不知道的JS:作用域是什么?

作者: 井润 | 来源:发表于2019-10-25 00:30 被阅读0次

    前段时间一直想抽空把《你不知道的JS》给看一看,准备好好巩固JS的基础,于是现在有了这篇文章.

    1.两个问题

    • 为什么讲作用域?
      • 讲作用域是因为大多数编程语言中,作用于都是非常关键的一环,它所提供的功能给我们编程程序的时候带来极大的便利!
    • 作用域在JS中的作用是什么?
      • 一套良好的规则来存储变量,并且与此同时,可以方便的找到变量,这套叫做作用域!

    看到这里的你,是不是以为现在就已经将我要讲的内容已经简单阐述完了,其实不是的,讲到这里其实是为了我们更好地理解作用域而做的铺垫.

    2.编译原理

    在我们学习JavaScript的过程中,常常看到书中提到几个比较鲜明的字眼,动态类型,解释型的编程语言!但是在本文中,我要说的是,JavaScript是一门编译类型的语言,尽管和你看到的Java等常见的编译类型语言不同!

    • 并非提前编译
    • 编译后的结果不能够在分布式中进行移植

    这两点适合传统的编译类型语言所不同的!虽然说JavaScript引擎编译和传统的编译语言步骤非常相似,但是在某些环节中比预想的还要复杂!

    传统编译语言流程中在执行前会经历的三个步骤,称为"编译"

    st=>start: start
    op1=>operation: 1.分词/词法解析
    op2=>operation: 2.解析/语法解析
    op3=>operation: 3.代码生成
    e=>end: end
    st->op1->op2->op3->e
    
    01编译.png

    那么对应的流程图中的概念如何理解呢?

    其实对应的也就是三个概念,我也只是结合自身的理解和书中的观点,进行简单阐述:

    • 分词/词法分析
      • 该过程会将字符串分割成为有意义的代码块! 至于说空格是否有意义,取决于空格在编程语言中是否有意义!
      • 其中有意义的代码块被称之为 词法单元!
    • 解析/语法分析
      • 该过程会将词法单元流(组)转换成为一个元素逐级嵌套组成代表程序语法结构的树!
      • 该树 被程序员们称之为 AST(Abstract Syntax Tree) 抽象语法树!
    • 代码生成
      • 将对应的AST转换为可执行代码的过程!
      • 对应的过程,与语言,目标平台息息相关!

    对应的比起编译过程只有三个步骤的语言的编译器而言,JavaScript引擎则复杂得多.

    • 在语法分析和代码生成阶段有特定的步骤对运行性能进行优化! 例如:对冗余元素进行优化!
    • JavaScript引擎不会有大量的时间进行优化,JS与别的语言不同的是,JS编译过程不是发生在构建之前的!
    • 编译发生在JS执行前几微秒,在作用域背后,JS引擎用了九牛二虎之力保证性能,其中包括以下几点:
      • JIT(Just In Time 即时编译)
      • 延迟编译
      • 实施重编译

    3.理解作用域

    • 引擎 从头至尾负责JS程序的编译和执行过程
    • 编译器 负责语法分析和代码生成
    • 作用域
      • 收集&维护 查询(由声明的标识符组成!)
      • 一套规则 确定当前执行代码对标识符的访问权限!

    首先我们看段代码:

    var a = 2;
    
    • 通过查看这段代码,有几次声明?

      • 编译器编译时的处理
      • 引擎运行代码时处理
    • 编译器是如何处理的呢?

      • 当开始遇到 var a的时候,编译器询问 作用域是否有一个该名称的变量存在于作用域的集合中!
        • 有的话 忽略声明 继续进行编译操作!
        • 否则 在当前作用域中的集合中生命新的变量!
      • 之后为引擎生成运行时所需的代码!
    • 引擎是如何处理的呢?

      • 引擎会询问作用于是否存在对应的变量,如果存在的话,使用该变量,否则继续查找该变量,该变量找不到的话就会报错!
    • 变量赋值操作会执行的两个动作

      • 编译器在当前作用域中声明一个变量(该变量存在的话!)
      • 运行时引擎会在作用域中查找该变量,找到就为其赋值!

    4.作用域嵌套

    在前面的内容中就已经说到过,作用于其实是一套规则,根据名称查找变量的一套规则,但是实际情况中还是很难避免需要同时估计几个作用域!

    当一个块或者函数嵌套在另外一个快或者函数中,就发生了对应的作用于嵌套,因此当我们查找某一个变量的时候无法找到的情况下,引擎就会向外层作用域查找,直到抵达最外层的作用域(全局作用域)为止!

    foo(a){console.log(a + b);}
    var b = 2;
    foo(2);
    

    其实通过这个例子就很明白的知道,在函数 foo中无法找到变量b,但是foo又是存在于全局作用域之下和b在同一个作用于,于是foo作用域找不到的变量在全局作用域中找到了!

    遍历作用域链的规则其实很简单,引擎从当前的执行作用域中开始查找该变量,如果找不到的话,就会向上一级查找,直到抵达全局作用域的时候,无论还有没有找到,查找过程都会停止!

    对应的我们为了更好的理解作用域的处理过程,嵌套作用域的处理过程向一个链条一样,此时这个链条就叫做作用域链!

    如果你有更好的建议或者意见,请在留言区告诉我 _!

    相关文章

      网友评论

          本文标题:你不知道的JS:作用域是什么?

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