今天做Ajax发现一个现象:Ajax部分刷新后,新生成的页面仍然能够调用刷新前页面的function。上网搜集资料后发现,该现象与JS的预编译有关。

–Brisk Yu

<script>
    var a = 1;
    function b() {
        alert(a);
        var a = 2;
        alert(a);
    }
    b();
</script>

观察以上JS代码,输出的结果是 undefined 和 2, 而不是 1 和 2。

1)当JS执行到<script>标签时会首先进入“预编译”阶段。此时解释器会:

  1 寻找var,将其作为window的属性,并赋值undefined;

  2 寻找function,将其作为window的属性,并将方法体赋值给它。

因此此时window对象看起来像是这样:

window = {
    //document等属性。。。
    a:undefined,
    b:function b() {
        alert(a);
        var a = 2;
        alert(a);
    }
}

2)此时开始逐行执行JS代码,执行完var a=1;后,window对象中的属性值被更新:

window = {
    //document等属性。。。
    a:1,
    b:function b() {
        alert(a);
        var a = 2;
        alert(a);
    }
}

3)接下来执行代码b(); 此时进入方法体后会再次进行预编译,即寻找var 和 function关键字。

此时会创建活动对象AO(Active Object)[2]

在一个函数对象被调用的时候,会创建一个活动对象,首先将该函数的每个形参和实参,都添加为该活动对象的属性和值;将该函数体内显示声明的变量和函数,也添加为该活动的的属性(在刚进入该函数执行环境时,未赋值,所以值为undefined,这个是JS的提前声明机制)[1]

此时function b的AO形如:

AO = {
    //arguments等属性。。。
    a:undefined     
}

4)逐步执行function b 中的代码。执行第一个alert时a:undefined,执行第二个alert时a:2。

5)综上所述,页面加载时,JS的预编译将var 和 function添加到了window对象作为其的属性。因此当Ajax部分刷新页面时,window对象的属性并没有变,所以新页面仍然能调用其方法。(我认为:JS执行方法不是到代码中去找方法体,而是去window对象中找是否有相关属性,其属性值即为方法体

参考资料:

[1] https://www.cnblogs.com/amy-fox/p/5856771.html

[2] https://blog.csdn.net/q1056843325/article/details/52951114

版权声明:本文为brisk原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/brisk/p/9629234.html