js 代码执行流程

我们都知道js代码是自上而下顺序执行,我们先来看一段代码

    test();
    console.log(str);
    var str = 'strtest';
    function test(){
      console.log(str)
    }  

这段代码会正常输出 undefind undefind, why?

    test();
    console.log(str);
    function test(){
      console.log(str)
    }  

再看,删除var str = 'strtest'; 会报错,why?说好的顺序执行呢?

别急,我们来了解JS 执行流程,尽管将JavaScript归类为“动态语言”或“解释执行语言”,但事实上它解释执行前需要编译。我们都知道计算机是不认识编程语言的,所有的编程语言都需要编译或解释为机器语言,那浏览器js引擎如何运行JS代码,JS运行分为三个步骤:1.词法语法分析 2.预编译 3.解释执行
(1)词法语法分析:无论你使用的是解释型语言还是编译型语言,都有一个共同的部分,将源代码作为纯文本解析为 抽象语法树(abstract syntax tree, AST) 的数据结构,词法语法分析这个阶段进行词法分析,语法检查(当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语法错误,并结束整个代码块的解析),并解析js代码生成 AST(抽象语法树)
(2)预编译
1)全局预编译过程
1.创建GO(Global Object全局对象)例如:window 或 global
2.查找变量声明作为GO的属性,并赋值为undefine;
3.查找函数声明,JS引擎会将函数定义部分存到堆(HEAP)中,并在GO中创建一个属性,并将该属性的值指向堆中函数的位置。
2)函数调用 — 函数预编译
1.创建AO对象
2.查找形参和变量声明作为AO属性,并赋值为undefine
3.实参赋值给形参
4.查找函数声明JS引擎会将函数定义部分存到堆(HEAP)中,并在AO中创建一个属性,并将该属性的值指向堆中函数的位置。
经过编译后,会生成两部分内容:执行上下文(Execution context,也可称执行环境包括:词法环境、变量环境、this绑定)和可执行代码。

image.png

在执行上下文中存在一个变量环境的对象(Variable Environment),该对象中保存了变量提升的内容,比如上面代码中变量str和函数test都保存在该对象中。
(3)解释执行
可执行代码顺序执行,当函数执行完毕且不存在其他作用域对其变量的引用,它所产生的执行上下文被销毁。

所以上面的第一段代码可正常执行输出undefined undefined,第二段代码str没有申明,到执行阶段的时候会报错。

如果代码中存在多个相同的变量和函数怎么办?

a(); // 1
console.log(a); // 2
var a = 'hello, world'; // 3
function a() { // 4
    console.log('inner a function 3')
}
var a = 'hello, tomorrow'; // 5
console.log(a); // 6
a(); // 7
function a() { // 8
    console.log('inner a function 2')
}

预编译

  1. 函数调用不做处理
  2. 函数调用不做处理
    3.有var变量声明,在执行环境中的变量环境对象上创建a变量并赋值为undefined
  3. JS引擎发现有function声明,把函数定义存储在堆中,并且在变量环境对象中寻找是否有a,有a,然后把a值指向该函数在堆中的位置。此时环境对象变成类似这样:
Variable Environent:
    a -> function () { console.log('inner a function 3')};
  1. 有var变量声明并且在变量环境对象中寻找是否有a,有a,不做处理。
    6.函数调用不做处理
    7.函数调用不做处理
    8.JS引擎发现有function声明,把函数定义存储在堆中,并且在变量环境对象中寻找是否有a,有a,然后把a值指向该函数在堆中的位置。此时环境对象变成类似这样:
Variable Environent:
    a -> function () { console.log('inner a function 2')};

执行阶段可执行代码顺序执行
执行结果:1.inner a function 2.function a() {
console.log('inner a function 2') 6. hello, tomorrow 7. a is not a function
}


image.png

如果函数有参数时怎么办?

a();  //1
a('hello tomorrow');  //2
function a(a){  //3
  console.log(a)  //3-1
  var a = 'inside'  // 3-2
}
var a = 'hello world'; //4
a(); //5

预编译
1.函数调用不错处理
2.函数调用不错处理
3.JS引擎发现函数声明,把函数定义存储堆中,在执行环境的变量环境对象中查找a,找到把a的值指向函数在堆中的位置
4.JS引擎发现var声明,在执行环境的变量环境对象发现a,不做处理
5.函数调用不做处理
执行阶段

  1. a函数调用,创建a的执行环境1
    a函数a的执行环境1预编译:
    创建执行环境1的变量环境
    变量环境对象中创建a形参赋值undefined, 无实参
    3-1.函数调用不处理
    3-2.JS引擎发现var声明,在a执行环境的变量环境对象中创建a并赋
    值 undefined
    a函数a的执行环境1执行:3-1 输出结果 undefined
  2. a函数调用,创建a的执行环境2
    a函数a的执行环境2预编译:
    创建执行环境2的变量环境
    变量环境对象中创建a形参赋值undefined
    3-1.函数调用不处理
    3-2.JS引擎发现var声明,在a执行环境的变量环境对象中创建a并赋
    值 undefined
    把实参赋值给形参a=’hello tomorrow'
    a函数a的执行环境1执行:3-1 输出结果hello tomorrow
  3. a = 'hello world'
  4. 报错 a is not a function
image.png

你可能感兴趣的:(js 代码执行流程)