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

最新文章

  1. mysql半同步复制问题排查
  2. maven实战(01)_搭建开发环境
  3. 正确理解javascript当中的面向对象
  4. NestIn VS插件 visual studio 中将同类CS文件放在一起显示
  5. WAMP启动失败简单解决方法
  6. 通过程序校验xml文档学习笔记
  7. PHP程序员面试技巧之口试题分享
  8. LA 2965 Jurassic Remains
  9. ajax的post用法
  10. git 实用命令
  11. Android Context创建过程
  12. zabbix 默认item采集使用被动模式 需要改为主动模式
  13. Mongo服务器集群配置【转】
  14. 快速构建Windows 8风格应用9-竖直视图
  15. Linux上安装二进制文件MySQL详解
  16. php simpleXML操作xml的用法
  17. WebApi-路由机制
  18. EDB日志配置-慢sql记录分析
  19. Tensorflow生成唐诗和歌词(上)
  20. C++11多线程教学

热门文章

  1. HTTP基本知识
  2. VUE-脚手架搭建
  3. Git:fatal: refusing to merge unrelated histories
  4. Tomcat日志与Log4j日志
  5. xBIM 日志操作
  6. es随想二
  7. 济南清北学堂游记 Day 5.
  8. [一个脑洞] Candy?&#39;s 不饱和度
  9. Python3 栈的实现
  10. 四、正则表达式re模块