JavaScript基础知识之函数的预编译

88 阅读3分钟

预编译

  • js运行三部曲
  1. 语法分析
  2. 预编译
  3. 解释执行

语法解析:js引擎在解析js代码之前,会先通篇扫描一下,找出低级的语法错误,比如写错大括号之类的

编译执行: 前面提到js是一周解释型语言,编译一行执行一行,当语法分析没问题,并且已经完成预编译阶段之后,就开始解释执行代码

这里着重介绍预编译

预编译前奏

提出两个需要掌握的概念

  1. imply global 暗示全局变量

如果任何变量未经声明就赋值使用,这个变量就会为全局对象window所有,并且成为window对象的一个属性

  1. 一切声明的全局变量,都是window的属性
  • 这样看不论全局变量有没有声明,似乎都会成为全局对象上的属性,那么两者之间有什么区别

区别在于:经过声明的全局变量不能通过delete操作来删除,但是未经生命的全局变量可以被删除

a = 123;
console.log(window.a === a) // trut
delete window.a
console.log(window.a); // undefined
var b = 123;
delete window.b
console.log(window.b) // 123

正式这种特性,导致es5有一种弊端,我们总会在无形中声明一些全局变量

function test () {
    var a = b = 0;
}

这段代码的原意是:在函数体中声明两个变量a、b,然后初始化a、b都是0。但是我们这么写之后,a经过了声明,但是b却没有声明,这时候b就会成为一个全局变量。

了解这两点之后,我们正式介绍一下预编译的过程。

预编译的过程我总结为以下四步:

  1. 创建AO对象。

  2. 寻找形参和变量声明,将变量声明和形参作为AO对象的属性添加到对象中,值为undefined。(注意函数声明不叫变量)

  3. 将实参值和形参值相统一。

  4. 在函数体里面寻找函数声明,将函数名作为属性名,值为这个函数的函数体

函数在执行的前一刻会产生一个上下文,这个上下文就是好Activeaction Object对象,见车过AO对象

AO = {}

这个对象是空的,但是里面有一些我们看不到的却存在的隐式属性,比如this window属性和argument:[]属性

这个对象用来存放一些属性和方法,这写实行和方法就按照前面的四部来产生

function test (a, b) {
  console.log a 
  function a () {}
  a = 222;
  console.log a
  function b () {};
  console.log b 
  var b = 111; 
  var a ;
}
test(1)

用这样一个样例代码,简单的介绍预编译的过程

首先第一步,创建AO对象

var AO = {}

第二步:寻找形参值和变量声明,并且将值赋为undefinde

AO = {
    a:undefined,
    b:undefined
}

第三步:将实参值和形参值相统一

AO = {
  a: 1,
  b: undefined
}

第四步:寻找函数声明,将函数体赋值给属性

AO = {
  a: function () {},
  b: function () {}
}

这样在编译执行之前,预编译阶段创建的AO对象就是这个样子了

  • 寻找变量声明的时候,不会管里面的代码到底会不会执行,执行是后面的事,这里只负责寻找所有的变量