相信你们在面试的过程当中常常遇到查看执行顺序的问题,如setTimeout,promise,async await等等,各类组合,是否是感受头都要晕掉了,其实这些问题最终仍是考察你们对js的运行机制是否掌握牢固,对promise,async的原理是否掌握,万变不离其宗,此次就来完全搞懂它。
js引擎也是程序,是属于浏览器的一部分,由浏览器厂商自行开发。从头至尾负责整个JavaScript程序的编译及执行过程面试
浏览器在渲染的过程当中,首先按顺序加载由<script>标签分割的js代码块,加载js代码块完毕后,须要js引擎进行解析。不管是外部脚本文件(不异步加载)仍是内部脚本代码块,都是同样的原理,而且都在同一个全局做用域中。JavaScript被归类为“动态”或“解释执行”语言,因此它无需提早编译,而是由解释器实时运行chrome
js引擎执行过程分为三个阶段:编程
js脚本代码块加载完毕后,会首先JS的解释阶段。该阶段主要过程以下:数组
最终计算机执行的就是机器码。promise
为了提升运行速度,现代浏览器通常采用即时编译(JIT-Just In Time compiler)浏览器
即字节码只在运行时编译,用到哪一行就编译哪一行,而且把编译结果缓存(inline cache)缓存
这样整个程序的运行速度能获得显著提高。安全
并且,不一样浏览器策略可能还不一样,有的浏览器就省略了字节码的翻译步骤,直接转为机器码(如chrome的v8)闭包
这里我理解为js为解释型语言,由解释器实时运行,通俗的说就是预处理完以后立刻执行,一边编译一边执行
function bar() { var B_context = "Bar EC"; function foo() { var f_context = "foo EC"; } foo() } bar()
这段函数通过词法解析,语法解析阶段以后,就开始进入预编译并执行,以下:异步
分析一段简单的代码,帮助咱们理解建立执行上下文的过程,以下:
function fun(a, b) { var num = 1; function test() { console.log(num) } } fun(2, 3)
这里咱们在全局环境调用fun函数,建立fun执行上下文,这里为了方便你们理解,暂时不讲解做用域链以及this指向,以下:
funEC = { //变量对象 VO: { //arguments对象 arguments: { a: undefined, b: undefined, length: 2 }, //test函数 test: <test reference>, //num变量 num: undefined }, //做用域链 scopeChain:[], //this指向 this: window }
注:建立变量对象发生在预编译阶段,但还没有进入执行阶段,该变量对象都是不能访问的,由于此时的变量对象中的变量属性还没有赋值,值仍为undefined,只有进入执行阶段,变量对象中的变量属性进行赋值后,变量对象(Variable
Object)转为活动对象(Active Object)后,才能进行访问,这个过程就是VO –> AO过程。
创建做用域链
做用域链由当前执行环境的变量对象(未进入执行阶段前)与上层环境的一系列活动对象组成,它保证了当前执行环境对符合访问权限的变量和函数的有序访问。
理清做用域链能够帮助咱们理解js不少问题包括闭包问题等,下面咱们结合一个简单的例子来理解做用域链,以下:
var num = 30; function test() { var a = 10; function innerTest() { var b = 20; return a + b } innerTest() } test()
在上面的例子中,当执行到调用innerTest函数,进入innerTest函数环境。全局执行上下文和test函数执行上下文已进入执行阶段,innerTest函数执行上下文在预编译阶段建立变量对象,因此他们的活动对象和变量对象分别是AO(global),AO(test)和VO(innerTest),而innerTest的做用域链由当前执行环境的变量对象(未进入执行阶段前)与上层环境的一系列活动对象组成,以下:
innerTestEC = { //变量对象 VO: {b: undefined}, //做用域链 scopeChain: [VO(innerTest), AO(test), AO(global)], //this指向 this: window }
在这里咱们顺便思考一下,什么是闭包?
咱们先看下面一个简单例子,以下:
function foo() { var num = 20; function bar() { var result = num + 20; return result } bar() } foo()
我这里直接以浏览器解析,以浏览器理解的闭包为准来分析闭包,以下图:
如上图所示,chrome浏览器理解闭包是foo,那么按浏览器的标准是如何定义闭包的,我总结为三点:
肯定this指向在全局环境下,全局执行上下文中变量对象的this属性指向为window;函数环境下的this指向却较为灵活,需根据执行环境和执行方法肯定