• 学习笔记=>《你不知道的JavaScript(上卷)》第一章:作用域是什么


    1.1 编译原理

      (1) JavaScript本质上也是编译型语言,和传统的编译语言(提前编译)的区别是它的编译是发生在执行前的,且

         编译的结果的不能在分布式系统中移植。

      (2) 传统编译语言流程中,一段源代码执行前要进行以下三个步骤(统称为编译):

         ①分词/词法分析 -----> ②解析/语法分析 -----> ③代码生成

         ① 分词/词法分析:代码编译的第一个步骤,这一阶段将一段待执行的js代码分解成有意义的代码(词法单元)

                      即:将我们写的代码分解成词法单元。

                   分词与词法分析的区别:分词和词法分析之间有非常微妙的区别,书中描述:

    “分词和词法分析之间的区别是非常微妙,晦涩的,主要的区别是词法单元的识别是通过有状态还是无状态的方式进行的,简单来说,如果词法单元生成器在判断a是一个独立的词法单元还是其他词法单元的一部分时,调用的就是有状态的规则,那么这个过程就被称为词法分析”

                  也就是:词法单元生成器使用有状态规则时即为词法分析,使用无状态规则时即为分词.

                   例:var a = 6; -----> ①var,②a,③=,④6,⑤;  

                   注:空格是否被当做词法单元取决于空格在这个语言中是否具有意义,像js里面多余空格

                     不会影响程序执行,应该就是在这一步骤(词法分析)中没有将多余的空格分解为词法

                     单元而是直接忽视掉。

            ② 解析/语法分析:书中描述:

    这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的,代表程序语法结构的树,这个树被称为 “抽象语法树”

                  也就是:将‘分词/词法分析’中得到的一组词法单元(数组格式)转换成“抽象语法树”

                  例:var a = 2;

          ③ 代码生成:书中描述

    将AST(抽象语法树)转换为可执行代码的过程称为代码生成,这个过程与语言,目标平台息息相关。简单来说就是有某种方法将var a = 2;的AST转化为一组机器指令,用来创建一个叫a的变量,并给它分配一个内存,将值2存入其中。

          总结:传统的编译型语言在执行前的编译中有三个步骤,即‘分词/词法分析’,‘解析/语法分析’,‘代码生成’。

             完整的编译步骤:一串代码 -----> 分解成一组词法单元 -----> 词法单元集合转换为抽象语法树 -----> 抽象语法树转换为机器指令

      (3)Js在执行前的编译与(2)中传统的编译类似,但是更复杂,例如在‘词法分析’和‘代码生成’阶段有特定的步骤优

          化运行时的性能,包括对冗余元素进行优化等。

    1.2 理解作用域

      (1)当浏览器处理一段程序的时候,涉及到三个模块,分别是‘引擎’,‘编译器’,‘作用域’,它们相互独立。

          书中描述:

    引擎:从头到尾负责JavaScript程序的编译和执行过程。

    编译器:引擎的好朋友之一,负责语法分析与代码生成这些脏活累活(即上一节中描述)。

    作用域:引擎的另一位朋友,负责收集并维护由所用声明的标识符(变量)组成的一系列查询,并实施一套严格的规范,确定当前执行代码对这些标识符的访问权限

          我的理解是:在一段程序的执行中,引擎是boss,编译器和作用域(根据名称查找变量的一套规则)是辅

                助,为引擎提供代码执行过程中必要的支持。

      
      (2)LHS和RHS:程序执行中,需要声明变量,变量赋值,变量获取时,通常是编译器和引擎在作用域系统

                   中的变量查询,查询分为LHS和RHS,对它们的区别我觉得最形象的是根据变量获取的目

                 的是什么来区分。当我们做赋值等操作,我们不需要关心变量内部存的值是什么而只需要

                 关心这个变量在作用域中存不存在的时候执行的就是LHS,反正当我们做计算等操作的时

                 候,我们主要想要获取的是变量中存的实际值的时候使用的就是RHS

        (3)例子:

    function foo(a){
        console.log(a);
    }
    
    foo(6);

            来分析一下这段代码中出现的LHS和RHS:

                ①foo(6);  //RHS----->调用foo函数,在作用域中查找是否存在这个函数,然后调用

                ②a = 6;  //LHS----->这是很容易被忽视的参数隐式赋值的地方,在作用域中查找变量a,并将6赋值给它

                ③cosnole.log(a);  //RHS----->在作用域中查找是否存在变量a,并将其传入log中

                ④console;  //RHS----->在作用域中查找是否存在console这个对象,并执行。

       总结:当执行一段JavaScript代码的时候,参与到其中的有三个模块‘引擎’,‘编译器’,‘作用域’。这三个模块相互

          独立,引擎为主,编译器和作用域为辅,代码中需要使用的变量在作用域中有两种查找方式LHS和RHS。

          当查找的变量用于赋值等不需要在意它的存值是什么子在意它是否在作用域中存在的时候使用LHS,反之使

          用RHS。

    1.3 作用域嵌套

      (1)作用域就是根据名称查找变量的一套规则,通常实际情况中作用域要同时维护多个作用域。当一个函数中嵌套另

          一个函数的时候就发生了作用域嵌套,这种情况下作用域会先在当前作用域中查找,当在当前作用域中找不到的

          时候会继续向上查找上一级作用域,直到最顶层的全局作用域这个时候无论找没找到都会停止。

    1.4 异常

      (1)为什么要区分LHS和RHS,当使用LHS和RHS查询都碰到作用域找不到的情况下的处理不同。

          LHS:当使用LHS查询规则的时候,如果直到全局作用域都没要找到的使用,全局作用域就会自动给我们在全局作

             用域下创建一个这个名词的变量,并把它返回给引擎,严格模式下由于不允许自动或隐式的创建变量,所以

             不存在这种情况,严格模式下会报ReferenceError(引用错误)。

          RHS:以上情况时,RHS规则会直接报ReferenceError(引用错误),如果找到的情况下,如果使用的方式和变量本身类型不匹配时会报TypeError。

  • 相关阅读:
    javascript中数据类型转换那些事
    CSS布局奇淫技巧之高度自适应
    用innerHTML插入html代码中有样式表时需注意的地方
    详解ASP.NET Core API 的Get和Post请求使用方式
    Speex 一个开源的声学回声消除器(Acoustic Echo Cancellation)(转)
    c# int byte转换
    Linux操作系统内核源码目录结构详解
    Linux/Ubuntu sudo不用输入密码的方法
    DirectX简介
    在VC工程中添加多语言支持
  • 原文地址:https://www.cnblogs.com/huangzhenghaoBKY/p/9773080.html
Copyright © 2020-2023  润新知