zoukankan      html  css  js  c++  java
  • JavaScript的预编译和执行

     JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行。所谓代码块就是使用<script>标签分隔的代码段。

    整个代码块共有两个阶段,预编译阶段和执行阶段

    一、编译阶段

    对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节生成。

    对于解释型语言(例如JavaScript)来说,通过词法分析和语法分析得到语法树后,就可以开始解释执行了。

    (1)词法分析是将字符流(char stream)转换为记号流(token stream),就像英文句子一个个单词独立翻译。

    (2)语法分析得到语法树,举例:

    条件语句 if(typeof a == "undefined" ){ a = 0; } else { a = a; } alert(a);


    当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语法错误,并结束整个代码块的解析。

    (3)“function函数”是一等公民!编译阶段,会把定义式的函数优先执行,也会把所有var变量创建,开辟内存空间,默认值为undefined,以提高程序的执行效率!(变量提升)

    当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理!并且是先预声明变量,再预定义函数!(变量提升是函数提升在变量提升前).

     

     JavaScript语法采用的是词法作用域(lexcical scope),也就是说JavaScript的变量和函数作用域是在定义时决定的(代码书写决定函数作用域,函数调用执行决定执行上下文和作用域链),而不是执行时决定的,由于词法作用域取决于源代码结构,所以 JavaScript解释器只需要通过静态分析就能确定每个变量、函数的作用域,这种作用域也称为静态作用域(static scope)。

     预编译在全局上下文前???

    二、JavaScript执行过程

    声明一个概念:执行上下文。即当前代码的执行环境,js 的运行环境包括:(1)全局环境(2)函数环境(函数被调用执行时,执行上下文推入函数调用栈)(3)eval,尽量避免使用

    例:var color="red";
    function getColor(){
        var anColor="blue";
        function chColor(){
            anColor=color;
        }
        chColor();
    }
    getColor();

    分析:开始函数调用栈栈底为全局上下文,当代码执行到getColor()时,将getColor()推入函数调用栈,执行到chColor()时,将chColor()推入函数调用栈。执行完后依次弹出。(return 可以直接终止代码执行,将当前上下文弹出函数调用栈)

    因此,函数在被调用后,产生执行上下文。

    产生执行上下文后到代码开始执行前,执行上下文会分别

     

    • 创建Scope chain
    • 创建VO/AO(variables, functions and arguments)
    • 设置this的值

    对于"创建VO/AO"这一步,JavaScript解释器主要做了下面的事情:

    • 根据函数的参数,创建并初始化arguments object
    • 扫描函数内部代码,查找函数声明(Function declaration)
      • 对于所有找到的函数声明,将函数名和函数引用存入VO/AO中
      • 如果VO/AO中已经有同名的函数,那么就进行覆盖
    • 扫描函数内部代码,查找变量声明(Variable declaration)
      • 对于所有找到的变量声明,将变量名存入VO/AO中,并初始化为"undefined"
      • 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
      • 在函数中新建的变量,变量对象中值为undefined
      • 
        
        function foo(i) {
            var a = 'hello';
            var b = function privateB() {
        
            };
            function c() {
        
            }
        }
        
        foo(22);
        
        VO
        
        
        fooExecutionContext = {
            scopeChain: { ... },
            variableObject: {
                arguments: {
                    0: 22,
                    length: 1
                },
                i: 22,
                c: pointer to function c()
                a: undefined,
                b: undefined
            },
            this: { ... }
        }
        AO
        fooExecutionContext = {
            scopeChain: { ... },
            variableObject: {
                arguments: {
                    0: 22,
                    length: 1
                },
                i: 22,
                c: pointer to function c()
                a: 'hello',
                b: pointer to function privateB()
            },
            this: { ... }
        }

      如果函数引用了外部变量的值,则JavaScript引擎会为该函数创建一个闭包体(closure),闭包体是一个完全封闭和独立的作用域,它不会在函数调用完毕后就被JavaScript引擎当做垃圾进行回收。闭包体可以长期存在。

    代码开始执行,这个特殊的活动对象(activation object) 就被创建了。它包含普通参数(formal parameters) 与特殊参数(arguments)对象(具有索引属性的参数映射表)。活动对象在函数上下文中作为变量对象使用。完成变量赋值函数引用执行后续代码。

    作用域链是一个 对象列表(list of objects) ,用以检索上下文代码中出现的 标识符(identifiers) 。
  • 相关阅读:
    MyStreamRequestHandlerr
    SocketFromServer
    MyQMainWindowDemo
    MyQThread
    Nginx安装与配置
    nginx软件优化
    MySQL优化实施方案
    tomcat优化方向
    Tomcat优化方案
    Nginx和Tomcat优化
  • 原文地址:https://www.cnblogs.com/ziqian9206/p/7074698.html
Copyright © 2011-2022 走看看