话不多说,先直接上题:请说出下面代码的执行结果
function fn(a){
var a=1
var a=2
function b(){}
var b=a
a=function c(){}
console.log(a);
c=b
console.log(c);
}
fn(3)
//结果:[Function:c] 2
对于能清楚地确定结果并解释原理的小伙伴,应该对预编译这个考点已经熟悉。在了解预编译之前我们需要知道一个小知识点——声明提升
声明提升
声明提升,就是在编译时,将当前作用域的变量的声明提升到这个作用域的顶端,也将函数的声明整体提升
foo()
function foo(){
console.log(a)
var a = 1
}
例如上面的代码,函数foo的调用在函数的声明之前,但是在编译时,foo的函数声明也就是整个函数体被提升到前面,再调用。在函数内部,console.log(a) 在变量a的声明之前,在编译时,会把a的声明提升到函数作用域的顶端,但是并不会执行赋值操作,所以打印的a的值为undefined,打印之后才执行赋值
预编译
预编译就是在代码执行之前,对代码进行编译,再执行代码操作,有函数预编译和全局预编译。
函数预编译
函数的预编译主要有四部曲,可以根据这四部曲去分析代码执行的结果
1.创建一个AO对象
2.找形参和变量声明,将变量声明和形参作为AO的属性名,值为undefined
3.将实参和形参统一
4.在函数体内找函数声明,将函数名作为A哦对象的属性名,赋予函数体
借此,我们用四部曲来分析开头的题目:
function fn(a){
var a=1
var a=2
function b(){}
var b=a
a=function c(){}
console.log(a);
c=b
console.log(c);
}
fn(3)
首先,函数的调用带来函数的编译,开始编译:(以下代码区只为了方便理解,不考虑运行)
第一步:创建一个AO对象: AO = {}
第二步:找形参和变量声明,将变量声明和形参作为AO的属性名,值为undefined: 形参是a,变量声明有var a; var b; 值都为undefined,相同属性名的会被覆盖只保留一个,即:
AO = {
a:undefined,
b:undefined
}
第三步:将实参和形参统一: 实参是3,形参是a,所以a的值为3,即:
AO = {
a:3,
b:undefined
}
第四步:在函数体内找函数声明,将函数名作为AO对象的属性名,赋予函数体: 函数体内内的函数声明有 function b(){} 和 function c(){} ,即:
AO = {
a:3,
b:function b(){},
c:function c(){}
}
到这里预编译就算完成,之后执行代码操作:赋值a为1,赋值a为2,再把a赋值给b,即:
AO = {
a:2,
b:2,
c:function c(){}
}
然后将 function c(){} 赋值给a,再打印a,即a的值就是 function c(){}
AO = {
a:function c(){},
b:2,
c:function c(){}
}
最后将b赋值给c,再打印c,即 c = 2
AO = {
a:function c(){},
b:2,
c:2
}
所以最终运行结果为:[Function: c] 2
全局预编译
全局预编译和函数预编译类似,但是只有三个步骤,因为全局没有参数
1.创建一个GO对象
2.找变量声明,将变量声明作为GO对象的属性名,值为undefined
3.在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体
可以举个例子分析一下:
global = 100
function fn(){
console.log(global);//undefined
global = 200
console.log(global);//200
var global=300
}
fn()
var global
第一步:创建一个GO对象: GO = {} 第二步:找变量声明,将变量声明作为GO对象的属性名,值为undefined: 这里只有一个变量声明 var global; 即:(以下代码区只为分析理解)
GO = {
global:undefined
}
第三步:在全局找函数声明,将函数名作为GO对象的属性名,值赋予函数体: 这里只有一个函数声明 function fn(){} ,即:
GO = {
global:undefined,
fn:function fn(){}
}
至此,全局预编译完成,开始执行全局代码:将global赋值为 100,即:
GO = {
global:100,
fn:function fn(){}
}
然后调用函数fn,所以开始执行函数预编译:
第一步创建AO对象,第二步找形参和变量声明,没有形参和函数体内的函数声明,即:
AO = {
global:undefined
}
函数预编译结束,开始执行函数内代码操作:先打印global,值为undefined,然后赋值global为200,再打印global,值为200,最后再赋值global为300,所以执行结果为:undefined 200
预编译在面试过程中也是比较容易遇到的,充分熟悉预编译的步骤了,就这?
最后,我们练习一下,可以把结果写在评论:
function fn(a, b) {
console.log(a);
c=0
var c
a=3
b=2
console.log(b);
function b(){}
function d(){}
console.log(b);
}
fn(1)
console.log(d);
d = 5
var d;