如上边示例,因为有预编译的存在,test() 的调用虽然在声明之前,函数也可以执行。这是为什么呢?引出 预编译前奏 这个概念:
预编译前奏:
imply global 暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局对象所有; eg: a = 123; eg: var a = b = 123; 一切声明的全局变量,全是 window 的属性。 eg: var a = 123;下图为一个实例,变量 a 虽然声明了,但不是全局变量,所以不能在函数体外访问到,但是变量 b 满足预编译前奏的第一点,未经声明就被赋值,此变量为全局对象所有,所以可以访问到。 知道了预编译前奏的概念,那么我们的理解就已经深入了一半了,顺着脉络继续。预编译前奏生成 GO(Global Object)对象,之后如果有函数就进行预编译,预编译四部曲如下:
预编译四部曲:
创建 AO 对象(Activation Object 俗称执行期上下文);找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined;将实参值和形参统一;在函数体里面找函数声明,值赋予函数体。通过简单的实例来认识一下 GO 与 AO 的结合:预编译前奏时,生成 window.b = 10;①预编译时创建 AO 对象;②将变量声明 a 放入 AO,值为 undefined;③传入参数,使得实参形参相统一,本例中没有形参;④如果函数体里还有函数声明,值赋予函数体,但是本例中没有。 最终,函数会打印出 undefined 。 再来一个例子,跟着我们前边的节奏来分析,先写下 GO 对象,再找 AO 对象。
<script type="text/javascript"> global = 100; function fn() { console.log(global); global = 200; console.log(global); var global = 300; } fn(); var global; </script>大家先来分析一下分别会输出什么呢?
我们来分析一下,global 未经声明就赋值,生成 GO 对象 global = 100;在执行到 fn() 的前一刻进行预编译,生成 AO 对象,其中只有 global,值为undefined,之后既没有实参的传入,也没有函数声明,那么第15行就打印 undefined了,经过16行之后,undefined 被修改为200 。所以两个答案分别是 undefined 和 200,你答对了吗?
题目一: 因为在函数 bar 最顶端return foo,那我们直接看到 AO 的第四部:返回函数声明,那么程序会打印 function foo()。
题目二: 这题和上一个类似,因为函数的最后返回 foo,而 foo 在上边被赋值过,那么 foo 一定为该值咯。 看完之后我们发现,其实预编译也并不难,再梳理一下:
底层基础决定上层建筑,这是不变的真理,深究原理绝对是没错的!
说在最后的话:编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~