js预编译解析执行过程分析

javascript编译解析执行顺序分析

先来看几道题,大家先猜一下alert的结果

1.

var a=2;
function show(){
window.setTimeout(function(){a=22},1000)
var a=4;
window.setTimeout(function(){ a=222},3000)
}

show();

alert(a);

==================================

2.

if ("a" in window) {
var a = 1;
}
alert(a);

=================================

3.

var a = 1;
function a() {
   
};
alert(a);

=================================

4.

function a(x) {
    return x ;
}
var a;
alert(a);

================================

5.

var a=3222;
function b(x, y, a) {
arguments[2] = 10;
alert(a);
}
b(1, 2, 3);
alert(a)

================================

先不说答案,我们先来分析一下js从加载到执行所经历的过程:

首先js加载完成之后 js引擎会对js代码有一个解析预编译过程,这个过程规则是:

对var关键字先提前声明(值先设为undefined,执行时才给实际值),接着对函数定义式进行提前加在var后头,

再接着顺序执行代码,函数定义式在预编译时期就被解析,执行时期仍然用这个值,而无论是声明的变量还是声明式函数,

在执行的时候,可以覆盖预编译时期的值

我们回过头去分析一下上面题目:

暂时跳过题目一,过会儿再说。

先看题目二:

if ("a" in window) {
var a = 1;
}
alert(a);

因为js没有块级作用域,所以if里面的也是全局的,所以在预编译过程中里面的变量a会被提出来并被赋值为undefined,

然后在执行if语句时候此时a已经存在于window中了,只不过值暂时是undefined,于是就会去执行if里面的代码,所以结果为1;

题目三:

var a = 1;
function a(x) {
};
alert(a);

预编译阶段寻找代码中的var(实际将var a=1拆分为var a;a=1两部分,第一部分置顶,第二部分挂在语法树上)以及function两个关键字并置顶,在此将a以及a()分别置顶;预编译阶段代码应该是这样的

var a;

a=function(x){}

之后在执行阶段再对a从语法树进行赋值,最后a为1,而不是一个函数;

题目四:

function a(x) {
    return x ;
}
var a;
alert(a);

这个题目跟上一个有点类似,但是却又不同,原因就是在这里a并没有被赋值,而只是声明一个变量;在预编译阶段会将这种形式提前置顶,然后将function也置顶,但是function在a之后,于是预编译后二者顺序完全倒过来了:

var a;
function a(x){};

所以最后执行结果是function a(x){};

如果显式的给a赋值一个a=undefined;那么结果就是undefined。因为此时牵扯到赋值了 赋值的话 就在执行阶段去执行

题目五:

var a=3222;
function b(x, y, a) {
arguments[2] = 10;
alert(a);
}
b(1, 2, 3);
alert(a)

这个题目实际跟预编译没有多少关系,只是考察函数参数作用域而已,首先在外层声明一个a变量,进而执行函数,函数内的a实际是参数而不是外界的a,在函数内部对a做任何操作都是对对应的参数a进行的操作;也就是arguments[item];

所以最后的结果是10,3222;

我们再回过头来看看题目一:

var a=2;
function show(){
window.setTimeout(function(){a=22},1000)
var a=4;
window.setTimeout(function(){ a=222},3000)
}

show();

alert(a);

我们分析一下这段代码,外部定义一个a变量并赋值为2,函数show()作用域内设置两个setTimeout事件以及声明了一个内部私有变量a。我们都知道内部私有变量跟外部的a是两码事,互不影响。难点就是setTimeout中定义的a到底是哪一只呢?

实际上这就牵扯到作用域链了,setTimeout中函数的指针this指向的是window,然而当前调用以及定义变量都是当前作用域,也就是作用域链的最近一层,在这里是show函数内部;show函数内部定义了a,于是setTimeout中的a就指向了内部的变量a;

所以两个setTimeout改变的a都是show函数内部的a值,跟外部全局中的a无关;所以最后alert出来的结果是2;

我们如果将内部的var a=4中的var去掉的话 这时候a就指向了全局变量中的a,同理setTimeout中的a也指向了全局变量a。这时候外部的a就会改变了。

以上题目全都取自互联网,自己分析如上,欢迎大家指教


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值