javascript之预编译

262 阅读4分钟

首先要记住:预编译发生在函数执行的前一刻

先来一个小知识:

  1. 函数声明整体提升
test();
function test(){
    ...//省略n行代码
}

在预编译阶段,会把函数声明提升到代码顶部:

function test(){
   ....    
}
test();
  1. 变量声明提升
console.log(a);
var a=123;

在预编译阶段,会把var声明提升到代码段的顶端:

var a;
console.log(a);
a=123;

控制台输出 undefined

但上面两点在遇到下面这种情况时就不够用了

function fn(a){
    console.log(a);
    var a=123;
    console.log(a);
    function a() {}
    console.log(a);
    var b=function () {}
    console.log(b)
    function d() {}
}
fn(1);

接下来就是预编译表演的时刻了:

  1. 创建AO(Activation Object----活跃对象)对象(另一个名称叫执行期上下文)
AO{
 
}
  1. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO{
 a:undefind,//形参和变量重名时,不需要重复创建
 b:undefind
}
  1. 将实参值和形参统一
AO{
 a:1,
 b:undefind
}
  1. 在函数体里找函数声明,函数名为AO属性名,值为函数体
AO{
 a:function a() {},//当函数名重名时,不需要重复创建,直接赋值即可
 b:undefind,
 d:function () {}
}

原函数变为(忽略变量声明与函数声明):

function fn(a){
    console.log(a);//从AO中取a的值为function a() {}
    a=123;//把123赋给给AO中的a
    console.log(a);//此时a为123
    console.log(a);//还是123
    b=function () {}//把函数体赋给AO中的b
    console.log(b)//function b() {}
    function d() {}
}
fn(1);

再来一个例子

function test(a,b){
    console.log(a);
    c=0;
    var c;
    a=3;
    b=2;
    console.log(b);
    function b() {}
    function d() {}
    console.log(b);
}
test(1);
  1. 创建AO对象
AO{
 
}
  1. 找形参和变量声明,将变量和形参名作为AO属性名,值为 undefined
AO{
 a:undefind,
 b:undefind,
 c:undefind
}
  1. 将实参值和形参统一
AO{
 a:1,
 b:undefind,
 c:undefind
}
  1. 在函数体里找函数声明,函数名为AO属性名,值为函数体
AO{
 a:1,
 b:function b() {},
 c:undefind,
 d:function d() {}
}

原函数变为(忽略变量声明与函数声明):

function test(a,b){
    console.log(a);//AO中a的值为1
    c=0;//0赋给AO中的c
    a=3;//3赋给AO中的a
    b=2;//2赋给AO中的b
    console.log(b);//AO中b的值为2
    console.log(b);//2
}
test(1);

练习:

function test(a,b){
   console.log(a);
   console.log(b);
   var b=234;
   console.log(b);
   a=123;
   console.log(a);
   function a() {}
   var a;
   b=345;
   var b=function b() {}
   console.log(a);
   console.log(b);
}
test(1);
AO{
    a:function a() {},
    b:undefind
}

(忽略变量声明与函数声明)

function test(a,b){
   console.log(a);//function a() {}
   console.log(b);//undefind
   b=234;
   console.log(b);//234
   a=123;
   console.log(a);//123
   b=345;
   b=function b() {}
   console.log(a);//123
   console.log(b);//function b() {}
}
test(1);

上面只是讲述在函数中的预编译,接下来加入全局的,中间插播一段作用域的小知识

  1. 一切声明的全局变量,都是 window 的属性
 var a = 3;   ===>   window.a = 3;
  1. 所有未经声明就赋值的变量都是全局变量
 1. a=3;
 2. var a = b = 3;//b未声明就赋值

回到我们的预编译

var a=123;
function a() {
    var a=b=3;
}
a();
  1. 生成一个GO(Global Object---全局对象)对象
GO{
    a:123,
    b=3;//未经声明的变量赋值为全局变量
}
GO ===> window
  1. 执行a(),生成AO对象

让我们来熟悉一下全局对象

var a=100;
function fn() {
    console.log(a);
}
fn();
  1. 生成GO
GO{
    a:100,
    fn:function fn() {}
}
  1. 执行fn()前一刻生成AO对象
AO{

}
  1. 执行fn()
首先在自己的AO中找a属性
AO{

}

AO中没有,去上一级GO中找
GO{
    a:100,
    fn:function fn() {}
}

找到a,控制台打印100

举个栗子:

console.log(test);
function test(test){
    console.log(test);
    var test=234;
    console.log(test);
    function test() {}
}
test(1);
var test =123;
  1. 生成GO,生成的过程步骤与AO一样
GO{
    test:function test() {}
}
console.log(test);//function test() {}
function test(test){
    ...
}
test(1);
var test =123;
  1. 执行到test(1)前一刻,生成AO
AO{
    test:function test() {}
}
  1. 执行test(1)(忽略变量声明与函数声明)
function test(test){
    console.log(test);//首先会在自己的AO中找是否有test属性,有就用自己的,没有就去GO中找,此时AO中有test,值为function test() {}
    test=234;
    console.log(test);//234
}

以上为本人观看成哥javascript视频教程后对预编译的总结,如有错误请指出。