今天学习到了一些关于预编译的相关知识,在这里和大家分享一下,如有错误请指出!
众所周知javascript是解释性语言,主要特点为解释一行执行一行。而在js运行时会进行三件事:
- 语法分析:在代码执行前对代码进行通篇检查,以排除一些低级错误
- 预编译:发生在代码执行的前一刻
- 解释执行:顾名思义就是执行代码
今天主要讲一下第二步:预编译。预编译也就是在代码执行的前一刻,会生成一个GO(Global Object)或者是AO(Active Object)对象。当然他们都有着自己的规则,首先我们来看AO规则。
1.AO
AO是针对函数的,AO规则主要分为四个步骤:
- 在函数执行的前一刻,会生成一个AO对象;
- 看参数。将形参作为AO对象的属性名,实参作为AO对象的属性值;
- 看变量声明。将变量名作为AO对象的属性名,值为undefined。如果变量名与形参名相同,就还是原来的值,不用管;
- 看函数声明。将函数名作为AO对象的属性名, 值为此函数体, 如果遇到同名(变量名或者形参名),就直接覆盖原来的值( 函数体去覆盖属性值)。
下面我们来看一个简单的例子:
function fun(a) {
console.log(a)
var a = 5;
console.log(a)
}
fun(10)
首先第一步生成一个空的AO对象:
AO={ }
第二步看参数:
AO={a:10}
第三步看变量声明:由于和形参名相同所以不管,还是
AO={a:10}
第四步看函数声明:这里没有所以没变,还是
AO={a:10}
当执行的时候就是10和5。因为执行第二次时重新赋值了,所以是5。
下面再来看个例子:
第一步生成一个空的AO对象:AO={ }
第二步看参数:AO={a:5}
第三步看变量声明:没有声明,还是AO={a:5}
第四步看函数声明:名称相同,函数体覆盖原来的值AO={a:function a(){console.log("hello");}}
当执行时候两次都是函数体function a(){console.log(“hello”);}。
这个例子和上面得类似,只不过函数声明变成了函数表达式,所以结果就不一样了,我们来分析一下:
第一步生成一个空的AO对象:AO={ }
第二步看参数:AO={a:5}
第三步看变量声明:有声明,现在不用管,还是AO={a:5}
第四步看函数声明:没有声明不变AO={a:5}
当执行时候第一次就是5,到第二次的时候进行了重新赋值,所以是函数体function a(){console.log(“hello”);}。
2.GO
接下来看看GO规则,比AO少一个步骤:
- 需要执行script代码前的一瞬间, 生成一个GO对象
- 看变量声明, 变量名为GO对象的属性名, 值为undefined
- 看函数声明, 函数名为GO对象的属性名, 值为函数体, 如果遇到同名( 变量名), 直接覆盖( 函数体去覆盖属性值)
同样用例子来说明:
console.log(a) //fun
var a = 10;
console.log(a) //10
function a() {}
console.log(a) // 10
var a = function() {}
console.log(a) //fun
第一步生成一个空的GO对象:GO={ }
第二步看变量声明:有声明,所以是GO={a:undefined}
第三步看函数声明:有同名的声明,函数体覆盖原来的值为GO={a:function a(){console.log(a)}}
执行时就是fun、10、10、fun。
下面来看一个综合的例子:
首先进行GO预编译
第一步生成一个空的GO对象:GO={ }
第二步看变量声明:有声明,所以是GO={a:undefined}
第三步看函数声明:有同名的声明,函数体覆盖原来的值为GO = { a: undefined, fun: function }
在执行阶段,执行第一行时变成了
GO = {
a: 99
fun: function
}
在第5行时fun调用了,函数在调用以后,执行之前,会生成一个AO对象
第一步生成一个空的AO对象:AO={ }
第二步看参数:AO={a:10}
第三步看变量声明:没有声明,还是AO={a:10}
第四步看函数声明:没有声明不变AO={a:10}
执行的时候就打印出a为10,最后一行打印的是全局的a为99。
今天就讲这么多,如果有疑问请评论私聊。