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. 理解DNS

    理解DNS 写在前面: 目前,我们大部分的网络通信都是基于TCP/IP协议的,而TCP/IP又基于IP地址作为唯一标识进行通信,随着需要记忆的IP地址数量的增多,肯定会超出我们的记忆能力范围,但如果使 ...

  2. Intellij IDEA 15 如何同时打开多个项目

    标题:Intellij IDEA 15 如何同时打开多个项目 作者原创技术文章,转载请注明出处 我们在编程时常常需要打开多个项目,例如操作复制黏贴或者参考其他项目等等,但是编译器Intellij ID ...

  3. ASP.NET MVC 5 ABP DataTables (一)

    1)ABP DataTables 应用(一) 2)  ABP DataTables 应用(二) JS DataTables 这个组件绑定数据必须要有自己的返回数据格式.但是ABP返回的格式直接绑定是错 ...

  4. NIO基础篇(二)

    Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管理多个网络连接. 传统的 ...

  5. BZOJ 4766: 文艺计算姬 [矩阵树定理 快速乘]

    传送门 题意: 给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二分图$K_{n,m}$ 求生成树个数 1 <= n,m,p <= 10^18 显然不能暴力上矩阵树定理 看 ...

  6. c语言中的#ifdef和#ifndef

    #include "stdio.h"#include "conio.h"#define MAX#define MAXIMUM(x,y) (x>y)?x:y ...

  7. php 数组变成树状型结构

    <? php $stime = microtime(true); $nodes = [ ['id' = > 1, 'pid' = > 0, 'name' = > 'a'], [ ...

  8. ionic2+Angular 使用HttpInterceptorService拦截器 统一处理数据请求

    sstep1:新建http-Interceptor.ts文件 import { Injectable } from '@angular/core'; import { HttpInterceptorS ...

  9. PHP基础点滴

    PHP基础点滴 双冒号::的用法: 双冒号操作符即作用域限定操作符Scope Resolution Operator可以访问静态.const和类中重写的属性与方法. 伪类型(pseudo-types) ...

  10. MySQL开启binlog并且保存7天有效数据

    开启binlog日志(在[mysqld]下修改或添加如下配置): server-id=1 log-bin=mysql-bin binlog_format=MIXED binlog日志模式 Mysql复 ...