我们都知道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绑定)和可执行代码。
在执行上下文中存在一个变量环境的对象(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')
}
预编译
- 函数调用不做处理
- 函数调用不做处理
3.有var变量声明,在执行环境中的变量环境对象上创建a变量并赋值为undefined - JS引擎发现有function声明,把函数定义存储在堆中,并且在变量环境对象中寻找是否有a,有a,然后把a值指向该函数在堆中的位置。此时环境对象变成类似这样:
Variable Environent:
a -> function () { console.log('inner a function 3')};
- 有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.函数调用不做处理
执行阶段
- a函数调用,创建a的执行环境1
a函数a的执行环境1预编译:
创建执行环境1的变量环境
变量环境对象中创建a形参赋值undefined, 无实参
3-1.函数调用不处理
3-2.JS引擎发现var声明,在a执行环境的变量环境对象中创建a并赋
值 undefined
a函数a的执行环境1执行:3-1 输出结果 undefined - 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 - a = 'hello world'
- 报错 a is not a function
网友评论