小白入门!学习基础之JavaScript中的预编译
前言
在上一篇文展中我们说到了函数声明会整体提升,而变量声明也会提升,可当二者同时出现时,到底哪一个会在顶部呢?
观察如下代码:
console.log(foo); // 输出: function foo() { return 'hello'; }
function foo() {
return 'hello';
}
var foo = 'world';

预编译的概念
预编译指的是JavaScript中的预编译是指在代码执行之前,JavaScript引擎会对代码进行一些准备工作,包括变量提升(hoisting)、函数声明提升、作用域的创建等操作。这个过程被称为预编译(Pre-compilation)或者解析(Parsing)阶段。
预编译发生在函数体内时(四部曲)
(一)创建函数的AO对象(Action Object)
(二)找形参和变量声明,将形参和变量声明作为AO的属性名,值赋予为undefined
(三)将形参和实参统一
(四)在函数体内找函数声明,将函数名作为AO对象的属性名,值赋予函数体
观察如下代码:
function fn(a){
console.log(a);
var a = 123
console.log(a);
function a() {}
console.log(a);
var b = function(){}
console.log(b);
function d(){}
var d = a
console.log(d);
}
fn(1)
此时按照预编译的步骤开始编译:
(一)创建函数的AO对象(Action Object)
AO={}
(二)找形参和变量声明,将形参和变量声明作为AO的属性名,值赋予为undefined
AO={
a:undefined
b:undefined
d:undefined
}
(三)将形参和实参统一
AO={
a:undefined,1
b:undefined
d:undefined
}
(四)在函数体内找函数声明,将函数名作为AO对象的属性名,值赋予函数体
AO={
a:undefined,1,function a() {}
b:undefined
d:undefined,function d() {}
}
预编译四个步骤结束后,AO对象的编译工作便结束了,开始执行代码,将console.log()对应的值输出来,并将各个变量的赋值执行上去
第一个console.log(a)输出时,此时a=function a() {}
AO={
a:undefined,1,function a() {}
b:undefined
d:undefined,function d() {}
}
第二个console.log(a)输出时,此时a的值的更新已被执行,则打印出a=123
第三个console.log(a)输出时,同第二个a一样,值已经被更新为123,所以a=123
AO={
a:undefined,1,function a() {},123
b:undefined
d:undefined,function d() {}
}
第四个console.log(b)输出时,b已由undefined被更新为function (){}
AO={
a:undefined,1,function a() {},123
b:undefined,function(){}
d:undefined,function d() {}
}
第五个console.log(d)输出时,d已经由function d(){}更新为a,而此时的a=123,所以d=123
AO={
a:undefined,1,function a() {},123
b:undefined,function(){}
d:undefined,function d() {},a
}

预编译发生在全局时(三部曲)
(一)创建GO对象(GLobal Object)
(二)找变量声明,将变量名作为GO的属性名,值赋予undefined
(三)在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体
观察如下代码:此段代码中既有全局编译也有函数体编译
global=100
function fu(){
console.log(global);
global =200
console.log(global);
var global = 300
}
fn()
var global;
开始全局编译(三部曲)
(一)创建GO对象(GLobal Object)
GO{
}
(二)找变量声明,将变量名作为GO的属性名,值赋予undefined
GO{
global:undefined
}
(三)在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体
GO{
global:undefined
fn:function fn(){}
}
此时全局编译便结束,开始执行代码........global的值被更新为100,执行fn()函数体,叫编译器来编译函数体。
GO{
global:undefined,100
fn:function fn(){}
}
开始函数体编译(四部曲)
(一)创建函数的AO对象(Action Object)
AO={
}
(二)找形参和变量声明,将形参和变量声明作为AO的属性名,值赋予为undefined
AO={
global=undefined
}
(三)将形参和实参统一
AO={
global=undefined //此时无实参,所以不变
}
(四)在函数体内找函数声明,将函数名作为AO对象的属性名,值赋予函数体
AO={
global=undefined //无函数声明,所以也不变
}
四部曲结束后,函数体的编译也结束了,现在开始执行函数,第一个console.log先在自己函数体内的上下文执行对象中(AO)找global,得知global=undefined,所以第一个console.log(global)输出undefined,当第二个console.log(global)执行前,global已被更新为200,所以第二个console.log(global)输出的值为200.
GO{ //全局上下文执行对象
global:undefined,100
fn:function fn(){}
}
AO={ //函数体上下文执行对象
global=undefined,200(在第一个console后,第二个console前更新为200),
300(最后更新为300)
}
总的来说,预编译阶段主要是对变量和函数声明进行提升,使得我们能够更好的理解Javascript这门语言的代码执行顺序与作用域。
以上便是今天学习讲解的所用内容,欢迎大家参与讨论与指点,最后感谢大家的浏览与支持!!!
转载自:https://juejin.cn/post/7362513291795628095