zoukankan      html  css  js  c++  java
  • 你不知道的Javascript(上卷)读书笔记之一 ---- 作用域

    你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些”坑”,在这里写一些博客记录一下笔记以便消化吸收。

    1 编译原理

    在此书中,开始便提出:Javascript是一门编译型语言,我一开始以为这是国内翻译的锅,翻译的不够准确,后来我还专门去github看了,作者确实是将Js描述为一门编译型语言(compiled language)。然而我认为作者更想表达的是Js也拥有和Java一般的特定的编译过程.而不是传统得认为只是单纯的进行”解释执行”。

    编译型语言的定义是编译型语言的首先将源代码编译生成机器语言,再由机器运行机器语言,就如C/C++一般。

    Java把源代码编译成为JVM可以执行的字节码,明显是不符合编译型语言的定义的,所以Java是一门解释型语言。而Javascript也拥有同Java类似的过程,但是这个过程很短。这它在代码执行前的几微秒内要完成程序的编译,然后马上执行。

    Javascript的编译分为三个步骤:

    a.分词/词法分析

    b.解析/语法分析

    c.代码生成

    Javascript在编译阶段的语法分析和代码生成阶段使用了各种方法(JIT, 延迟编译, 重编译等)保证性能最佳。

    2 理解作用域

    书中所说的Javascript的解释和执行的过程,主要就几个角色参与:

    引擎:负责编译的第一部分(分词/词法分析)和执行编译后生成的代码

    编译器:负责编译的第二部分(语法分析)和编译的第三部分(代码生成)

    作用域:负责收集所有声明的标识符,即变量,并且维护一套管理变量的规则
    对于var a = 2;可以认为他的执行过程如下

    a.引擎执行编译的第一步 分词/词法分析

    b.引擎调用编译器,编译器进行编译的语法分析和代码生成

               a) 编译器遇到var a,去当前的作用域集合中查找是否存在a这个变量

               b) 如果存在,则忽略变量声明

               c) 如果不存在,则在作用域中声明一个新的变量,命名为a

               d) 生成引擎运行所需代码

    c.引擎运行生成的代码

                a) 去当前作用域中查找是否存在a变量,如果找不到这个变量,它会继续往上 (它的上一层作用域)寻找

                b) 如果存在,会使用这个变量,并为这个变量赋值

                c) 如果不存在,会抛出一个异常或者创建一个变量(*详细请看下文LHS和 RHS)

    备注:引擎去作用域查找变量的方式有两种一种是LHS查询,另外一种是RHS查询。

    a) LHS可以认为是代表取得变量的源地址(变量实际上就是计算机内存中一段连续 的地址,并且我们通过为变量命名来为这段内存地址命名),取得源地址用于为该变量赋值。

    b) RHS代表查询得到变量的值,一般用于为其他变量赋值

    直接说LHS和RHS肯定太抽象,也不好记,LHS 和 RHS 字面上区别在于 L 和 R,分别代表左(left)和右(right)

    对于 a= b = 2 这行代码,代码首先为b赋值为2。然后呢?重点来了

    1首先查询得到b的值

    2把查询的得到的值赋给a

    而这,恰好分别对应着RHS查询和LHS查询,首先对处于右边的b进行一次RHS(查询得到b的值),然后LHS查询找到a变量的源地址(为a赋值)。

    函数的执行,比如foo(2),实际是对foo进行一次RHS,得到的值是函数类型的对象,然后去执行他时,还有一次(多个形参时就是多次)对形参的LHS

    3 作用域嵌套

    当一个块或函数嵌套在另外一个块或函数中时,就发生了作用域的嵌套,因此,如果我们在一个块中定义函数的话,函数执行过程中是可以调用到函数外层的变量的。

    整个的函数作用域链就像一个金字塔,在书中作者把函数作用域链比喻为一个建筑。在作用域的最顶层是一个全局作用域,每一个作用域都可能包含数个子作用域,如此往下延伸,因此金字塔对函数作用域链会更贴切。

    LHS和RHS都会先在当前作用域进行查找,如果没有找到结果,那么它们都会一直往上寻找,直至全局作用域。

    4 异常

    如果引擎在最顶层的全局作用域中也找不到,那么会有什么行为呢? 在这里的话,LHS和RHS会有不同的行为

    a.对于LHS:如果在最顶层也找不到这个变量,如果在非严格模式下,那么会在全局 作用域创建一个全局变量,如果处于严格模式下,严格模式禁止自动或隐式创建全 局变量,此时会抛出ReferenceError异常

    b.对于RHS:如果在最顶层也找不到这个变量,那么会抛出ReferenceError异常。如果对查询的变量进行不合理的操作,比如调用非函数对象,会抛出TypeError异常。

  • 相关阅读:
    redis 五种数据结构详解(string,list,set,zset,hash)
    推荐一个同步Mysql数据到Elasticsearch的工具
    一些经验,用来鉴别不太靠谱的公司或工作(面试是双向的,是你最好的了解这个公司的机会)
    OpenSSL 使用 base64 编码/解码(liang19890820)
    Qt之QEvent(所有事件的翻译)
    Go 在 Windows 上用户图形界面 GUI 解决方案 Go-WinGUI 国产(使用cef 内核)
    卷积神经网络CNN
    Event Driven Architecture
    wineshark分析抓取本地回环包
    僵尸进程与孤儿进程
  • 原文地址:https://www.cnblogs.com/butter-fly/p/6111620.html
Copyright © 2011-2022 走看看