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) 。

JavaScript的预编译和执行的更多相关文章

  1. javascript的预编译和执行顺序

    原文:javascript的预编译和执行顺序 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题 代码: 代码一<html> ...

  2. JS的预编译和执行顺序 详析(及全局与局部变量)

    最近在复习javascript的事件处理时发现了一个问题,于是总结一下:javascript的预编译和执行顺序的问题:   <html> <head> <title> ...

  3. JS的预编译和执行顺序 详析

    原文:JS的预编译和执行顺序 详析 最近在复习javascript的事件处理时发现了一个问题,然后也是我来写javascript的预编译和执行顺序的问题   代码:   复制代码 代码一 <ht ...

  4. 关于JavaScript预编译和执行顺序以及函数引用类型的思考

    昨晚在对项目中的一部分做模块化处理的时候,遇到了一个问题,一个重新定义的function对一个通用类中的function进行赋值覆盖的时候,失败了.问题抽象出来是这样的: <script > ...

  5. javascript预编译和执行过程总结

    javascript相对于其它语言来说是一种弱类型的语言,在其它如java语言中,程序的执行需要有编译的阶段,而在javascript中也有类似的“预编译阶段”(javascript的预编译是以代码块 ...

  6. JavaScript 之 预编译 作用域,作用域链

    第一次写博客,本来是学习jQuery遇到闭包问题,发现并没有理解闭包,发现闭包牵扯的知识点太多.复习了一遍(发现自己该记住的全忘了)写在博客里,自己也是小白,希望大神们指点迷津,必将感激不尽. 我们知 ...

  7. 一步一步的理解javascript的预编译

    首先,我们要知道javascript是单线程.解释性语言.所谓解释性语言,就是翻译一句执行一句.而不是通篇编译成一个文件再去执行. 其实这么说还没有这么直观,读一句执行一句那是到最后的事了.到JS执行 ...

  8. JavaScript之预编译

    javascript是一种解释性弱类型语言,在浏览器中执行时,浏览器会先预览某段代码进行语法分析,检查语法的正确与否,然后再进行预编译,到最后才会从上往下一句一句开始执行这段代码,简单得来说可以表示为 ...

  9. JS 的预编译和执行顺序

    脚本执行js引擎做的工作: 语法分析 预编译 解释执行

随机推荐

  1. js调用系统虚拟键盘

    <input type="text" id="tt" /> <script language="javascript" t ...

  2. hexo 博客支持PWA和压缩博文

    目标网站 https://blog.rmiao.top/ PWA yarn add hexo-offline 然后在root config.yml里新增 # offline config passed ...

  3. linux下iptables配置模板

    linux下iptables配置模板 # Flush all policy iptables -F iptables -X iptables -Z iptables -t nat -F iptable ...

  4. androidstudio canary5一个bug

    Android Studio最新开发版一直跟着升级.到Canary5的时候出了一个bug. app build.gradle添加自己编译的aar库,原本一直使用: compile(name:'ijkp ...

  5. ipcs、ipcrm、sysresv、kernel.shmmax

    ipcs.ipcrm.sysresv.kernel.shmmax 1.1  BLOG文档结构图 1.2  前言部分 1.2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可 ...

  6. Kafka Consumer

    Push VS Pull An initial question we considered is whether consumers should pull data from brokers or ...

  7. Java程序只运行一个实例[转]

    如果希望你的Java程序只能存在一个实例,可以参考下面的用法. 原文链接:http://blog.csdn.net/yaerfeng/article/details/7264729 Java没有提供这 ...

  8. Eclipse远程调试应用程序

    第一步,在应用程序的配置文件run.xml中加入下面的配置项,启动应用程序: <target name="run" depends="checkBuilderFai ...

  9. vue中如何获取后台数据

    原文链接:http://blog.csdn.net/vergilgeekopen/article/details/68954940 需要引用vue-resource 安装请参考https://gith ...

  10. UOJ#77. A+B Problem [可持久化线段树优化建边 最小割]

    UOJ#77. A+B Problem 题意:自己看 接触过线段树优化建图后思路不难想,细节要处理好 乱建图无果后想到最小割 白色和黑色只能选一个,割掉一个就行了 之前选白色必须额外割掉一个p[i], ...