Javascript中的预编译

一、前言

写这个的目的是笔者对于js变量提升一直心存疑惑,原谅我这么菜hhhhh

二、预编译在什么时候发生

预编译分为全局预编译和函数预编译:全局预编译发生在页面加载完成时执行,而函数预编译发生在函数执行的前一刻。

三、全局预编译的步骤

  • 创建GO(Global Object,全局执行期上下文,在浏览器中为window)对象;
  • 寻找var变量声明,并赋值为undefined;
  • 寻找function函数声明,并赋值为函数体;
  • 执行代码。

一个小案例
我们先来看一下下面这段代码:

var x = 1,
    y = z = 0;

function add (n) {
  return n = n + 1;
}

y = add(x);
function add (n) {
  return n = n + 3;
}

z = add(x)

接下来我们来按照前面的步骤详细分析它的预编译执行过程:

//1.创建一个GO对象
GO{
    // 对象内容为空
}

寻找var变量声明,并赋值为undefined

Go{
    x: undefined
    y: undefined
    z: undefined
}

寻找function函数声明,并赋值为函数体

GO{
   x: undefined
   y: undefined
   z: undefined
   add: function add (n) { return n = n + 1; } => function add (n) { return n = n + 3; }
}

按顺序执行代码

var x = 1,
    y = z = 0;

function add (n) {
  return n = n + 1;
} //预编译环节已经进行了变量提升,故执行时不在看这行代码

y = add(x);
function add (n) {
  return n = n + 3;
}//预编译环节已经进行了变量提升,故执行时不在看这行代码,但是这一函数覆盖了前面的add函数

z = add(x)

故而我们的GO对象变成了

GO{
   x: 1
   y: 0
   z: 0
   add: function add (n) { return n = n + 3; }
}

所以我们可以知道,此时x的值为1,y的值为4,z的值为4

四、函数预编译的步骤

  • 创建AO对象,执行期上下文(后面更新关于执行期上下文详解)。
  • 寻找函数的形参和变量声明,将变量和形参名作为AO对象的属性名,值设定为undefined.
  • 将形参和实参相统一,即更改形参后的undefined为具体的形参值。
  • 寻找函数中的函数声明,将函数名作为AO属性名,值为函数体。

一个小案例

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);

接下来我们来按照前面的步骤详细分析它的预编译执行过程:

创建AO对象

AO{
    // 空对象
}

寻找函数的形参和变量声明,将变量和形参名作为AO对象的属性名,值设定为undefined.

AO{
    a: undefined,
    b: undefined
}

将形参和实参相统一

AO{
    a: 1,
    b: undefined
}

寻找函数中的函数声明,将函数名作为AO属性名,值为函数体。

AO{
    a: function(){}
    b: undefined
    d: function(){}
}

函数开始逐行顺序执行:

function fn(a){
    console.log(a);// 输出functiona(){}
    var a = 123;
    console.log(a);// 输出123
    
    function a(){};//预编译环节已经进行了变量提升,故执行时不在看这行代码
    console.log(a);// 输出123
    
    var b = function(){};//这个是函数表达式不是函数声明,故不能提升,会对AO中的b重新赋值
    console.log(b);//输出function(){}
    
    function d(){};
 }

结果在代码块的注释里

一个综合案例

var a = 1;
console.log(a);
function test(a) {
  console.log(a);
  var a = 123;
  console.log(a);
  function a() {}
  console.log(a);
  var b = function() {}
  console.log(b);
  function d() {}
}
var c = function (){
console.log("I at C function");
}
console.log(c);
test(2);

全局预编译

GO{
    a: undefined,
    c: undefined,
    test: function(a) {
        console.log(a);
        var a = 123;
        console.log(a);
        function a() {}
        console.log(a);
        var b = function() {}
        console.log(b);
        function d() {}
    }
}

按顺序执行代码

GO{
    a: 1,
    c: function (){
        console.log("I at C function");
    },
    test: function(a) {
        console.log(a);
        var a = 123;
        console.log(a);
        function a() {}
        console.log(a);
        var b = function() {}
        console.log(b);
        function d() {}
    }
}

执行到test(2),函数开始预编译

3.1

AO{
    a: undefined,
    b: undefined
}

3.2

AO{
    a: 2,
    b: undefined
}

3.3

AO{
    a: function(){},
    b: undefined,
    d: function(){}
}

执行结果

var a = 1;
console.log(a); // 1
function test(a) {
  console.log(a); // function a() {}
  var a = 123;
  console.log(a); // 123
  function a() {}
  console.log(a); // 123
  var b = function() {}
  console.log(b); // function b() {}
  function d() {}
}
var c = function (){
console.log("I at C function");
}
console.log(c); // function c(){ console.log("I at C function"); }
test(2);

以后遇到关于预编译的相关问题,大家就可以按照上面的步骤进行解决了,还有就是如果大家在遇到的代码里有if语句的话,在预编译阶段先无视他就可。希望这篇文章能够帮助到和我一样迷惑的你!

原文链接:https://juejin.cn/post/6844904110999732232

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值