javascript 预编译 作用域

本文主要是讲预编译。

1. undefined 
当需要判断一个变量是否为 undefined 时,直接用

Js代码
  1. alert(om == undefined);  


可能出错。因为 JS 如果引用未声明的变量,那么会出现JS错误,在上述例子中,如果 om 未曾声明,就会报 JS 错误。因此判断一个变量是 undefined,最好用这种方法

Js代码
  1. alert( typeof om == 'undefined' );  



2. JS 中没有块作用域,在函数中声明的变量在整个函数中都可用(无论是在函数开头处声明还是末尾处声明),如

Js代码
  1. function () {   
  2.       alert(om);        // 显示 undefined   
  3.       var om = 'abc' ;   
  4.       alert(om);        // 显示 abc   
  5. }  



3. JS 在函数执行前将整个函数的变量进行声明,无论这个变量的声明语句有没有机会执行,如

Js代码
  1. function () {   
  2.     alert(om);       // 显示 undefined   
  3.     if false ) {               
  4.         var om = 'abc' ;      // 此处声明没有机会执行   
  5.     }   
  6. }  

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

 

今天工作需要,搜索下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>  


问执行完毕后 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>  

那么这时 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>  


会分别弹出 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> 块执行正常,结果就是弹出 "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>  

执行结果如何呢? 
在 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>  

执行结果是"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>  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值