JavaScript预编译的13个知识点

213 阅读3分钟

JavaScript引擎的两大步骤:

  • 预编译(第一次/前置扫描) — 变量 函数等声明
  • 解释执行(第二次扫描)

预编译 - 脚本
脚本:

  • 创建全局对象GO(Global Object)

  • 加载脚本文件 预编译:

  • 找出所有的变量声明,按照变量名加入全局对象,如果已经存在,忽略。

  • 找出所有的函数声明,按照函数名加入全局对象,如果已经存在同名变量或者函数,替换。

解释执行

脚本的预编译
1.如果遇到没有var的变量,都不是变量声明,全部都认为是局部变量,不参与预编译。
示例代码:

console.log(aa);
aa = 5;
console.log(aa);

2.即使aa在函数中,aa也是全局变量,是运行时生效,不是预编译时生效。

console.log(aa);
test();
function test(){
	aa = 5;
     // console.log('Hello!');
}
console.log(aa);

3.脚本中,所有的变量声明,在脚本的预编译阶段完成,所有的变量声明与实际的书写位置无关。

console.log(a);   // undefined
var a = 5;
console.log(a);		// 5

4.脚本中,所有的函数声明,在脚本的预编译阶段完成,所有的函数声明与实际的书写位置无关。

console.log(f);
function f(){
    console.log('哈哈');
}

5.脚本中,如果变量与函数同名,那么函数将覆盖变量

console.log(f);  // 输出函数
var f = 123;
console.log(f); // 输出变量  被赋值影响
function f(){
    console.log('哈哈哈');
}
console.log(f); // 输出变量

6.脚本中,如果变量与函数同名,函数可以覆盖变量,变量无法覆盖函数。

console.log(f); // 输出函数
function f(){
    console.log('hahha');
}
var f = 123; 

7.脚本中,如果有多个函数同名,最后声明的函数将覆盖所有前面的同名函数声明。并且,参数个数是忽略的,也就是说,JS压根不支持重载。

console.log(f);
function f(x){
	console.log('haha1')
}
function f(x,y){
	console.log('haha2')
}

预编译 - 函数调用
函数调用:
创建活动对象AO(Active Object)
预编译:

  • scope chain
  • 初始化arguments
  • 初始化形参,将arguments中的值赋值给形参
  • 找出所有的变量声明,按照变量名加入AO,如果已经存在,忽略。
  • 找出所有的函数声明,按照函数名加入AO,如果已经存在同名变量或者函数,替换。

解释执行

8.函数中,所有变量声明,在函数的预编译阶段完成,所有变量的声明与实际的书写位置无关

function f(){
  console.log(a);
  var a = 25;
  console.log(a)
}
f();

9.函数中,所有函数声明,在函数的预编译阶段完成,所有函数的声明与实际的书写位置无关。

function f(){
    console.log(fin);
    function fin(){
       console.log('hahha');
   }
}
f();

10.函数中,如果变量与函数同名,那么函数将覆盖变量

function f(){
     console.log(fin);
     var fin = 123;
     console.log(fin);
     function fin(){
         console.log('haha');
     }
 }
f();

11.函数中,只有函数能够覆盖变量,变量无法覆盖函数

function f(){
      console.log(fin);
      function fin(){
         console.log('haha');
      }
      var fin = 123;
     }
f();

12.函数中,如果有多个函数同名,最后声明的函数将覆盖所有前面的同名函数声明。并且,参数个数是忽略的,也就是说,JS压根不支持重载。

 function f(){
     console.log(fin);
     function fin(x){
         console.log('haha1');
     }
     function fin(x){
        console.log('haha2');
     }
 }
 f();

13.当函数预编译后,遇到需要访问的变量或者函数,优先考虑自己AO中定义的变量和函数。如果找不到,才会在其定义的上一层AO中寻找,直至到GO,再找不到才报错。

  var scope = 'global';
  function f(){
     console.log(1,scope);   // undefined
     var scope = 'local';
     console.log(2,scope);   // 'local'
 }
  f();
  console.log(3,scope);   // 'global'

JavaScript的预编译是个比较重要的知识点,大家要结合代码深入理解一下。