几乎全部的编程语言均可以存储,访问,修改变量,那在JavaScript中这些变量放在那里?程序如何找到他们?编程
js被归类于解释执行语言,但事实上他也是一门编译语言,由于他也要编译,但于传统的编译语言不一样,他不是提早编译,编译结果也不能在分布式系统中进行移植。但js引擎编译的步骤和传统的编译语言很是类似。编程语言
传统的编译会经历3个步骤:分布式
对于传统的编译过程,js引擎要复杂的多,js编译发生在执行前的几微秒,而后作好执行他的准备,而且一般立刻就会执行他。函数
说道这仍是没有说这些变量放在那里?下面介绍3位大佬:spa
这时候答案就浮出水面。啊,是这伙计--做用域.prototype
做用域?大哥你哪来的啊?上面提到做用域像一个容器同样收集并维护全部标识符(变量和函数)事实上他是一个对象,收集的东西挂在它的属性上。做用域的出生是由于函数的产生而产生的。当函数执行的前一刻的时候,会建立一个做用域,这个做用域定义了这个函数执行时的环境,函数每次执行时的做用域都是独一无二的,由于他是对象啊,就像出生的孩子长得都不太同样。这个做用域小名特别多,什么执行期上下文,AO(Activation Object)对象,活动对象。做用域这帮伙计们有个头叫--全局做用域。里面的做用域能看到外面的,哈哈,你在我面前就是个小透明,但外的做用域可看不到里面的。指针
在js高程里解释道做用域。code
做用域是因函数产生而产生的,每一个对象都有属性和方法,函数(function)也是一种特殊的对象,函数能够有test.name test.prototype ...这些是能够访问的,还有一些属性是不能够访问的隐式属性仅供JavaScript引擎处理。 好比[[scope]]:指的是做用域链,其中存储了执行期上下文的集合。这个集合呈现链式链接,咱们把这种链接叫作做用域链。做用域链本质上是一个指向变量对象的指针列表,他只是引用,但不包含实际变量对象。.[[scope]]这里面存的就是做用域。系统会根据内部的原理去按期调用scope。当函数执行的前一刻的时候,会建立一个称为执行期上下文的内部对象(AO activation object)。一个执行期上下文定义了一个函数执行时的环境。函数每次执行时对应的上下文都是独一无二的,即便执行同样的函数可是执行期上下文并不相同,因此屡次调用一个函数会致使建立多个执行上下文,当函数执行完毕,他所产生的执行上下文会销毁。对象
上面还提到了编译,说道js编译发生在执行前的几微秒。也讲到变量和函数会放到做用域的问题,事实上,是这样的,在程序执行前不是要进行编译的吗,在引擎和编译器两位大哥的帮助下 ,在编译时(函数执行前)会处理声明的变量和函数,把他挂到做用域这个对象的属性上。这个过程叫 -- 见下行。blog
预编译
当你看见var a = 2;这段程序时,极可能认为这是一句声明,事实上咱们引擎这哥们认为有两个彻底不一样的声明,一个由编译器在编译时处理,另外一个在引擎运行时处理。
代码执行前会对其进行编译,首先编译器会分词,而后解析成语法树,最后进行代码生成,别忘了代码生成就是将语法树转化为一组机器指令。
也就是说变量和函数在内的全部声明都会在任何代码被执行前首先被处理。--先编译,在执行。
console.log(a); //undefinde var a = 2; console.log(a); //2
这也解释了为何第一行没有报错的缘由。
首先代码执行前一刻进行编译,var a; console.log(a); a = 2; console.log(a);相似这样的执行顺序(就好像变量和函数从他们的代码中出现的位置被移动到了最上面)。 编译器看到var a会查看当前做用域是否有变量a,没有声明一个变量a,开始执行代码(js是顺序执行)。
当函数和变量同名时,函数会覆盖变量。
由此预编译过程能够总结成一下过程
预编译四部曲: