了解js的运行机制有助于咱们在平常的工做中,写成高质量的代码,减小bug的产生,节约维护成本。也有助于咱们经过造火箭的面试。 javascript
了解运行机制以前,咱们先来搞清楚几个基本概念。css
渲染是根据描述或者定义构建一个数据模型,生成图形的过程。渲染引擎将页面资源(html、css、javaScript等)构建成可视化、可听化的多媒体结果。也就是咱们看到的浏览器网页呈现。 html
当咱们在运行一段代码时,真正赋予这段代码生命的就是JavaScript引擎。JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,通常会附带在网页浏览器中。JavaScript引擎从头至尾负责整个JavaScript程序的编译和执行过程。java
最为你们熟知的无疑是V8引擎,他用于Chrome浏览器和Node中。node
若是想让一段JavaScript代码真正的运气起来,单单靠JavaScript引擎是不够的,JavaScript Engine的工做是编译并执行 JavaScript 代码,完成内存分配、垃圾回收等,可是缺少与外部交互的能力。面试
好比单靠一个V8引擎是没法进行ajax请求、设置定时器、响应事件等操做的,这就须要JavaScript运行时(JavaScript Runtime)的帮助,它为 JavaScript 提供一些对象或机制,使它可以与外界交互。ajax
好比,虽然Chrome和node都是用了V8引擎,可是他们的运行时却不一样,好比process、fs浏览器都没法提供。浏览器
一段javaScript代码的运行咱们能够分为两个阶段。bash
接下里咱们主要说说,JavaScript的执行阶段。数据结构
JavaScript既是编译语言,又是解释语言。JavaScript引擎实际上在执行代码前仅几微秒就编译了代码。
称为JIT(及时编译)。它自己是一个很大的话题。可是如今,咱们能够跳过编译背后的理论,而只关注执行阶段,这仍然颇有趣。
JavaScript引擎,编译和解释咱们的JavaScript代码。JavaScript引擎其实也包含了不少较小的部分,这些较小的部分,分工合做来保证JavaScript的运行。
先看一段代码
var num = 2;
function pow(num) {
return num * num;
}
复制代码
看到这段代码,你们思考一下会发生什么。可能你们已经想到JavaScript引擎,在执行到第一行代码时就马上讲引用放入全局内存(Global Memory)。全局内存是JavaScript引擎保存变量和什么函数的地方。当引擎读取以上代码时,全局内存将填充两个绑定:
var num = 2;
function pow(num) {
return num * num;
}
pow(num);
复制代码
当咱们执行函数的时,JavaScript引擎会用到调用堆栈(Call Stack)。调用堆栈是一个堆栈类的数据结构,意味着它是先进后出的执行方式。若是是多个函数,将依次进栈,先进后出。
当代码块在执行时,JavaScript引擎会建立一个执行上下文,已做为代码运行的基础运行环境。
在"4.2.1代码块",有三种代码块,分别对应三种执行上下文
基础执行上下文,一个程序只有一个全局执行上下文,任何不在函数内部的代码都在全局执行执行上下文。全局执行上下文只要作两件事情:
若是咱们的函数有一些嵌套变量或一个或多个内部函数怎么办?
var num = 2;
function pow(num) {
var a = 1,
b = 2,
c = 3;
function add(a, b, c) {
return a + b + c;
}
}
复制代码
每当一个函数被调用时,都会为该函数建立一个新的上下文。每一个函数都有它本身的执行上下文,不过是在函数被调用时建立的。函数上下文能够有任意多个。每当一个新的执行上下文被建立。
执行在 eval 内部的代码也会有它属于本身的执行上下文,请不要、不要、不要轻易使用它。
执行上下文也分为建立和执行阶段。在建立阶段就很是有意思了。
执行上下文的建立阶段主要作了三件事:
在建立可执行上下文的时候,根据代码的执行条件,来判断分别进行默认绑定、隐式绑定、显示绑定等。
this绑定也是有优先级的,优先级规则以下:
词法环境是JavaScript引擎内部用来跟踪标识符和特定变量之间的映射关系。词法环境是Js做用域的实现机制。若是以前了解过做用域概念的话,和词法环境是相似的(ES6以后做用域概念变为词法环境概念)。
做用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说做用域最大的用处就是隔离变量,不一样做用域下同名变量不会有冲突。 ES6 以前 JavaScript 没有块级做用域,只有全局做用域和函数做用域。ES6的到来,为咱们提供了‘块级做用域’,可经过新增命令let和const来体现。
词法环境中含有外部词法环境的引用,咱们能够经过这个引用获取外部词法环境的变量、声明等,这些引用串联起来一直指向全局的词法环境,所以造成了做用域链。
词法环境中含有外部词法环境的引用,咱们能够经过这个引用获取外部词法环境的变量、声明等,所以造成了闭包。
查看大量资料都没有详细的记录变量环境。
ES5标准文档中规定,执行环境包括:词法环境、变量环境、this绑定。其中执行环境的词法环境和变量环境组件始终为词法环境对象。当建立一个执行环境时,其词法环境组件和变量环境组件最初是同一个值。在该执行环境相关联的代码的执行过程当中,变量环境组件永远不变,而词法环境组件有可能改变。
变量环境的不变和词法环境的可能改变都是指引用的改变,规范12.10和12.14两部分的内容提到了词法环境在with以及catch语句块中会改变。
JavaScript既是编译语言,又是解释语言。可是JavaScript本质上是一种解释型语言,与编译型语言不一样的是它须要一边执行一边解析,而编译型语言在执行时已经完成编译,可直接执行,有更快的执行速度。
参考: