参考文献:https://blog.csdn.net/q1056843325/article/details/52951114
JavaScript引擎运行的三大步骤
- 语法分析。
- 预编译(第一次\前置扫描)
- 解释执行(第二次扫描)
严格说Js是解释性语言、没有编译即使有JIT也是V8引擎做的,JS预编译是第一次扫描把声明的东西变量放在名字表里。
脚本大概步骤
创建全局对象GO(window) (上下文)
加载脚本文件
预编译:
- 找出所有的变量声明,按照变量名加入全局对象,如果已经存在,忽略。
- 找出所有的函数声明,按照函数名加入全局对象,如果已经存在同名变量或者函数,替换(后面会覆盖前面的函数或变量)。
- 非声明不予理睬
解释执行。
注意:函数的预编译在调用的时候先执行预编译。
预编译、举例子1
<script>
//Javascript脚本的预编译
//1.没有var的变量,全部认为是window的全局变量,不参与预编译
console.log(aa);
aa=5;
console.log(aa);
</script>
结果:Uncaught ReferenceError: aa is not defined
原因:在预编中没有发现任何东西,在执行中第一个console.log
打印aa的时候aa没有被定义,所以包语法错误。
//Javascript脚本的预编译
//1.没有var的变量,全部认为是window的全局变量,不参与预编译
console.log(aa); //undefined
var aa=5;
console.log(aa); //5
原因:1、生成了全局对象GO、然后开始扫描找到变量和函数声明并加入全局对象中,2、开始解释执行,因为在预编中aa已经加入GO对象中、但并没有初始化,所以第一个console.log()出现了undefined在,在下一行aa被赋值成5,所以一个console.log结果是5。这种机制有个好处就是,在函数定义后可以在函数的前面进行调用。
预编译、举例子2
//Javascript脚本的预编译
//2.即使在函数中,a也是全局变量、是运行时,不是定义时。
function test(){
a=5;
}
console.log(a);
Uncaught ReferenceError: a is not defined,
原因:同上面,1、预编译的时候扫到了test这个函数,但没有扫到a。执行的时候test没有调用,console.log
的时候a没有定义所以出错
<script>
//Javascript脚本的预编译
//2.即使在函数中,a也是全局变量、是运行时,不是定义时。
test();
function test(){
a=5;
}
console.log(a); //5
</script>
结果是 :5
原因:1、第一次预编译的时候扫描到了test函数声明,没有扫到a。2.执行test()函数,函数进行预编译,函数预编译没有结果。执行时window对象下加入了a全局变量并赋值等于5,函数销毁。执行console.log时结果等于5。
//Javascript脚本的预编译
//2.即使在函数中,a也是全局变量、是运行时,不是定义时。
test();
function test(){
var a=5;
}
console.log(a); //Uncaught ReferenceError: a is not defined,
原因:同第二个demo中的第一个一样的错误,因为函数执行中进行了预编译和解释执行,但函数声明周期销毁var a也销毁了,所以a报了错误。====此问题涉及到了作用域链的问题
补充:脚本中,所有变量声明,在脚本的预编译阶段完成,所有变量的声明与实际的书写位置无关
预编译、举例子3
<script>
console.log(haha);
function haha(){
console.log('h1');
}
</script>
结果:把函数打印出来了。原因和例子1是一样的。
补充:脚本中,所有函数声明
,在脚本的预编译阶段
完成,所有函数的声明
与实际的书写位置无关。脚本中如果函数和变量同名、那么函数会覆盖变量、只有函数能覆盖变量、变量无法覆盖函数。
<script>
console.log(haha);
var haha="123";
function haha(){
console.log('h1');
}
var haha="321";
</script>
脚本中,后面的函数声明会覆盖前面的函数声明,并且忽略参数
<script>
console.log(haha);
function haha(a){
console.log('haha1');
}
function haha(a,b){
console.log('haha2');
}
</script>