今天工作需要,搜索下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 在执行前会进行类似"预编译"的操作,而且先预定义变量再预定义函数。