理解Javascript中的预编译


今天工作需要,搜索下JS面试题,看到一个题目,大约是这样的
Js代码

1. <script>
2. var x = 1, y = z = 0;
3. function add(n) {
4. n = n+1;
5.   }
6.
7. y = add(x);
8.
9. function add(n) {
10. n = n + 3;
11. }
12.
13. z = add(x);
14. </script>

<script>
var x = 1, y = z = 0;
function add(n) {
n = n+1;
  }

y = add(x);

function add(n) {
n = n + 3;
}

z = add(x);
</script>


问执行完毕后 x, y, z 的值分别是多少?

仔细看的人马上就知道了, x, y 和 z 分别是 1, undefined 和 undefined。

不过,如果将两个 add 函数修改一下,题目变为
Js代码

1. <script>
2. var x = 1, y = z = 0;
3. function add(n) {
4. return n = n+1;
5.   }
6.
7. y = add(x);
8.
9. function add(n) {
10. return n = n + 3;
11. }
12.
13. z = add(x);
14. </script>

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


那么这时 y 和 z 分别是什么呢?我马上想到是 2 和 4,不过结果却是 4 和 4。
这说明,在第一次调用 add 函数之前,第二个 add 函数已经覆盖了第一个 add 函数。原来,这是 JS 解释器的"预编译",JS 解析器在执行语句前会将函数声明和变量定义进行"预编译",而这个"预编译",并非一个页面一个页面地"预编译",而是一段一段地预编译,所谓的段就是一个 <script> 块。且看下面的代码
Js代码

1. <script>
2. function add(n) {
3. return n = n+1;
4.   }
5. alert(add(1));
6. </script>
7.
8. <script>
9. function add(n) {
10. return n = n+3;
11.   }
12. alert(add(1));
13. </script>

<script>
function add(n) {
return n = n+1;
  }
alert(add(1));
</script>

<script>
function add(n) {
return n = n+3;
  }
alert(add(1));
</script>


会分别弹出 2 和 4。

那么,将上面的题目再变换一下,如下
Js代码

1. <script>
2. alert( typeof addA);
3. addA();
4. function addA() {
5. alert( "A executed!" );
6. };
7. </script>
8. <script>
9. alert( typeof addB);
10. addB();
11. var addB = function () {
12. alert( "B executed!" );
13. };
14. </script>

<script>
alert(typeof addA);
addA();
function addA() {
alert("A executed!");
};
</script>
<script>
alert(typeof addB);
addB();
var addB = function() {
alert("B executed!");
};
</script>


执行结果是什么呢? 按照前面的知识,第一个 <script> 块执行正常,结果就是弹出 "function" 和 "A executed!" 的对话框。
那么第二个 <script> 块呢? 执行结果是弹出 "undefined" 的对话框后报 JS 错误,说 addB 不是一个 function。
有点出乎意料?呵呵,其实第一个 script 块中的 addA 一句是函数声明,当然进行了"预编译",但是第二个 script 块中的 addB 一句并非函数声明。只不过在执行这段 <script> 之前对变量进行了"预声明",因此一开始变量addB是存在的,只不过是 undefined 的(可参看http://eclipse07.iteye.com/admin/blogs/484566 )。因此执行结果便如上面所示。

将题目再变化下,如下
Js代码

1. <script>
2. alert( typeof addB);
3. addB();
4. var addB = function addB() {
5. alert( "B executed!" );
6. };
7. </script>

<script>
alert(typeof addB);
addB();
var addB = function addB() {
alert("B executed!");
};
</script>


执行结果如何呢?
在 ff 下执行,与上面执行结果一样。打住,且在 IE6 下执行看看如何。
结果是弹出 "function" 和 "B executed!",一切正常。
Google 了一下,有人说这是 IE 的 BUG。

那么,请看下面的代码
Js代码

1. <script>
2. alert( typeof addB);
3. var addB = "variable" ;
4. function addB() {
5. alert( "function addB" );
6. }
7. alert(addB);
8. </script>

<script>
alert(typeof addB);
var addB = "variable";
function addB() {
alert("function addB");
}
alert(addB);
</script>


执行结果是"function"和"variable"。
JS解析器先预定义了 addB 变量为 undefined, 但是 addB 函数覆盖了此变量,因此一开始执行结果是 function,然后 addB 被赋值为 "variable",因此最后执行结果是 "variable",上面的代码即使变为
Js代码

1. <script>
2. alert( typeof addB);
3. function addB() {
4. alert( "function addB" );
5. }
6. var addB = "variable" ;
7. alert(addB);
8. </script>

<script>
alert(typeof addB);
function addB() {
alert("function addB");
}
var addB = "variable";
alert(addB);
</script>


结果也一样,这说明JS解析器先预声明变量,再预定义函数 。
小结一下:JS 在执行前会进行类似"预编译"的操作,而且先预定义变量再预定义函数。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值