一.基本概念
引擎:从头到尾负责javaScript程序的编译及执行过程
编译器:负责语法分析,代码生成
作用域:负责收集并维护所有声明的标识符(变量)组成的一系列查询,并实施一条非常严格的的规则,确定当前执行的代码对这这些标识符的访问权限
词法作用域: 作用域有词法作用域和动态作用域之分,javaScript的作用域是词法作用域,特征是它的定义过程发生在代码的书写阶段,在编译阶段会确定作用域对象
二.执行前:
javaScript 是一门“解释型”语言么,也是一种编译语言,执行前通常会经过两步
1⃣️语法分析:语法分析过程会构造一棵抽象语法树(AST)
2⃣️代码生成(编译阶段):代码生成会将AST转换成可执行的代码
1.语法分析阶段:
如果分析遇到一个语法错误,就会抛出一个语法错误语法错误(syntaxError),停止js代码的执行,然后继续查找并加载下一个代码块;如果语法正确,则进入到预编译阶段。
2.编译阶段:
js运行环境包括:
全局环境(js代码加载完毕后,进入到预编译也就是进入到全局环境)
函数环境(函数调用的时候,进入到该函数环境,不同的函数,函数环境不同)
每进入到不同的运行环境都会创建一个相应的执行上下文,一段js程序中一般会创建多个执行上下文,js引擎会以栈的数据结构对这些进行去处理,形成函数调用栈,栈底永远是全局执行上下文,栈顶永远是当时的执行上下文。
创建执行上下文主要做了三件事:
1⃣️创建变量对象(variable object)
创建arguments对象,仅在函数环境(非箭头函数)中进行,全局环境没有此过程
检查当前上下文的函数声明,找到的函数提前声明,如果当前变量对象没有存在该函数名属性,则在该变量对象以函数名建立一个属性么,属性值将执行该函数所在堆地址引用,如果存在将会被新的引用覆盖掉
检查当前上下文的变量声明,将找到的变量提前声明,如果当前上下文的变量对象没有变量名属性,则在该变量对象以变量名建立一个属性,属性值为undefined;如果存在,则忽略该变量声明
2⃣️创建作用域链
作用域链由当前执行环境的变量对象(未进入到执行阶段前)与上层环境的一系列活动对象(执行后变为活动对象)组成,保证了当前执行环境对符合访问权限的变量和函数有序访问。
3⃣️确定this的指向
三.执行阶段:
JS是单线程的,为了实现非阻塞,它采用了异步机制
JS是单线程的,为了实现非阻塞,它采用了异步机制
所用到的线程:
1⃣️Js引擎线程:执行js的主线程,主js执行完成之后会去读取事件队列中的事件,推入执行栈,进行执行,如此往复称为事件循环
2⃣️事件触发线程(onclick,onload等):归属于浏览器内核进程,用于控制事件,事件触发时会将事件的处理函数推进事件队列
3⃣️定时器触发线程,由主js线程调配,用于计时,计时完毕,该线程会将回调函数推入事件队列
4⃣️http异步请求线程,XMLHttpRequest连接后,通过浏览器的新开一个请求线程,如果有回调函数,会在请求结果回来之后,将回调函数推进事件队列
执行顺序为:宏任务(同步)-》所有的微任务 -〉宏任务(异步)
浏览器环境的微任务:promise
举个例子:var a = 2; console.log(a);
概念:
变量的赋值过程分为两个阶段,首先编译器会在编译阶段在作用域中查找是否有名称为a的变量,如果找到则忽略该声明,否则将声明一个新的变量,注意只是声明,然后引擎在运行阶段就会在作用域中查找这个变量,如果能找到就会对他进行赋值。
引擎查询是还有一个概念:
LHS查询,RHS查询,LHS查询出现在赋值操作符左侧的变量,也就是“赋值操作的目标” RHS是指非左侧是指“找到赋值操作的源头”或者“得到XXX的值“
例子中:
第一句对a是一个LHS引用,第二句是对a的一个RHS引用
作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。
赋值操作符会导致 LHS 查询。=操作符或调用函数时传入参数的操作都会导致关联作用域 的赋值操作。
JavaScript引擎首先会在代码执行前对其进行编译,在这个过程中,像var a = 2这样的声 明会被分解成两个独立的步骤:
1. 首先,var a 在其作用域中声明新变量。这会在最开始的阶段,也就是编译阶段进行。
2. 接下来,a = 2 会查询(LHS 查询)变量 a 并对其进行赋值,在执行阶段进行。
LHS 和 RHS 查询都会在当前执行作用域中开始,如果有需要(也就是说它们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一级作用域(一层楼),最后抵达全局作用域(顶层),无论找到或没找到都将停止。
不成功的 RHS 引用会导致抛出 ReferenceError 异常。不成功的 LHS 引用会导致自动隐式 地创建一个全局变量(非严格模式下),该变量使用 LHS 引用的目标作为标识符,或者抛 出 ReferenceError 异常(严格模式下)。