<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>js执行顺序</title>
</head>
<script type="application/javascript">function hello(){
  alert('hello,zhangsan');
}
hello();//第一次调用,猜猜输出什么内容?
function hello(){
   alert('hello,lisi');
}
hello();//第二次调用,猜猜输出什么内容?var hello = function(){
alert('hello,zhangsan');
}
hello();//第一次调用,输出“hello,zhangsan”
var hello = function(){
alert('hello,lisi');
}
hello();//第二次调用,输出“hello,lisi”
</script><body>
</body>
</html>
教材上写的是"JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。而且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行。函数定义执行完后,才会按顺序执行其他",

var hello = function(){
alert('hello,zhangsan');
}

var hello = function(){
alert('hello,lisi');
}同样都是定义式的函数语句,为什么他们不会被优先执行?

解决方案 »

  1.   

    var hello = function()
     这种定义模式实际上是定义一个匿名函数,再将函数的引用指向hello所以函数确实定义了,但是在解析这一行之前,你无法调用。
      

  2.   

    原文:Javascript作用域备忘本文主要是讲预编译。1. undefined
    当需要判断一个变量是否为 undefined 时,直接用
    Js代码   1. alert(om == undefined);  alert(om == undefined);
    可能出错。因为 JS 如果引用未声明的变量,那么会出现JS错误,在上述例子中,如果 om 未曾声明,就会报 JS 错误。因此判断一个变量是 undefined,最好用这种方法
    Js代码   1. alert( typeof om == 'undefined' );  alert(typeof om == 'undefined');2. JS 中没有块作用域,在函数中声明的变量在整个函数中都可用(无论是在函数开头处声明还是末尾处声明),如
    Js代码   1. function () {   
       2.       alert(om);        // 显示 undefined   
       3.       var om = 'abc' ;   
       4.       alert(om);        // 显示 abc   
       5. }  function() {
            alert(om);       // 显示 undefined
            var om = 'abc';
            alert(om);       // 显示 abc
       }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>  <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.javaeye.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 在执行前会进行类似"预编译"的操作,而且先预定义变量再预定义函数。
      

  3.   

    var tem=function(){}
    tem相当于一个函数指针,指向下面的函数调用。
      

  4.   

    哦 有些懂了,我把程序的执行顺序写了一遍,能不能麻烦你们看下是不是这样:
    程序的实际执行顺序:
    第一段语句执行:
    function hello(){
      alert('hello,zhangsan');
    }
    function hello(){
       alert('hello,lisi');
    }
    //导致function hello()被覆盖
    hello();//输出hello,lisi
    hello();//输出hello,lisi
    第二段语句执行
    var hello = function(){
    alert('hello,zhangsan');
    }//指向匿名A函数
    var hello = function(){
    alert('hello,zhangsan');
    }//指向匿名B函数
    hello();//输出指向匿名A函数的hello,显示hello,zhangsan
    hello();//输出指向匿名B函数的hello,显示hello,lisi
      

  5.   

    哎呀,问题又来了,我发现了矛盾唉
    按照
    理论A:“
    JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。而且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行。函数定义执行完后,才会按顺序执行其他
    ”来说,定义的函数会被优先执行,但是下面的例子
    function () {   
       alert(om); // 显示 undefined   
       var om = 'abc' ;   
       alert(om); // 显示 abc   
       }
    程序的实际执行顺序应该是
       var om='abc';
       alert(om); 
       alert(om);
    那么应该都是显示abc abc
    但结果却是 显示 undefined   显示 abc
    是不是说理论A错误的?
      

  6.   

    谢谢老胡老师,我看了很久,但依然觉得有些云里雾里,我把我理解的复述一遍:
    对于function函数,优先运行,等function函数运行完毕后,再运行var的定义语句,但仅仅是预定义(即只是把该变量预定义为undefined),之后再按原代码顺序运行其他语句
    上代码:
    <script>
      alert(typeof addA);
      addA();
      function addA() {
      alert("A executed!");
      };
    </script>
      优先执行function
      function addA() {
      alert("A executed!");
      };
      按顺序执行其他代码:
       alert(typeof addA);
      addA();
      很容易理解:输出为function,A executed!
    <script>
      alert(typeof addB);
      addB();
      var addB = function() {
      alert("B executed!");
      };
    </script>
      优先运行匿名函数
      function() {
      alert("B executed!");
      };
      有定义语句var,对addB进行预定义(addB=undefined)
      按顺序执行其他语句
       alert(typeof addB);
      addB();
      var addB = function() {
      alert("B executed!");
      };
      解释addB为undefined,故输出undefined
      当执行adB()时,系统报错而我上一楼中所说
      function () {   
      alert(om); // 显示 undefined   
      var om = 'abc' ;   
      alert(om); // 显示 abc   
      }
      有var语句,预定义om为undefined
      所以解释了前一个为undefined,后一个在赋值后输出abc不知我的解释是否有误?
      

  7.   

    5L:
    你理解偏了。给你翻译一下你的理论A:
    JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。:
    程序员敲出的代码肯定是逐行向下进行的,例如:
    <script type='text/javascript'>
    1 function jeffstric() 
    2  alert(om);
    3  var om = 'abc' ;  
    4  alert(om);
    5}
    6jeffstric();
    7alert('你明白了?')
    </script>
    所谓“执行引擎并非一行一行地分析和执行程序”是说,在上例中程序不会按照1-> 2-> 3-> 4-> 5-> 6-> 7这样的顺序逐行执行;
    所谓“而是一段一段地分析执行的。”:你把一段理解为一块,意思一样。上例中那一对蓝色花括号{}就是“块”的定义符;换句话说,就是{}中的程序是一个整体(一个“块”),执行时不可分割;所谓“定义式的函数语句会被提取出来优先执行。函数定义执行完后,才会按顺序执行其他”:简单的说就是上面说的那个函数块{}中的代码在程序中被调用的时候会被一次提取出来执行掉。现在说说这个例子:
    1、首先<script type='text/javascript'> </script>告诉计算机,<script>标签内是一段javascript脚本语言。计算机开始调用JS解释引擎;2、逐行读代码:
    第1行:function jeffstric() :引擎发现了这个是一段jeffstric函数体和块首符号{,  因为没有调用,所以找块尾符号}在第5行,从而将整块代码跳过;第6行:jeffstric();引擎见到了刚才的函数体jeffstric,并发现了“()”这个执行符号,于是返回头去到第2行执行函数块,而不是“顺序的”执行第7行的alert('明白了?');于是,你的问题就出在这里:
    第2行  alert(om); 你这个om显然是个变量,但并没有被定义,所以是alert出来undefined
    第3行 定义了om;
    所以第4行alert出来“abc”
    第五行 引擎见到了},知道“块”结束了。于是回到第6行的下一行,那就是:
    第7行:“你明白了?”
      

  8.   

    你的代码好有针对性,压力有点大啊,不过你写的我是理解了^O^谢谢理上网来老师的解释
    另外呢,我还有个疑问:理论A“
    JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。而且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行。

    中你仅解释了1:"是一段一段地分析执行的" 还没解释道2:"定义式的函数语句会被提取出来优先执行。"
    我对2的理解是:

    对于function函数,优先解释,解释完毕后再解释var的定义语句,但仅仅是预定义(即只是把该变量预定义为undefined)

    不知我的解释是否正确,恳请指正!
      

  9.   


    hello();//hello,lisi
    function hello(){
      alert('hello,zhangsan');
    }
    hello();//hello,lisi
    function hello(){
       alert('hello,lisi');
    }
    hello();//hello,lisihi();//出错 hi is not a function
    var hi = function(){
    alert('hello,zhangsan');
    }
    hi();//第一次调用,输出“hello,zhangsan”
    var hi= function(){
    alert('hello,lisi');
    }
    hi();//第二次调用,输出“hello,lisi”
      

  10.   


    关于你2的理解,其实有点错误那个匿名函数其实已经在内存了,只是没有具名(function () {}) 
    function xx() {}
    都会预定义2个函数,一个只不过有明确变量指向,一个没有变量指向你可以想想xx()的理解是xx + () 先找xx指向的内容,然后将内容按照函数的方式调用那么就会理解
    function xx(){}
    xx();
    var xx = function() {};其实 先找var 定义的变量,定义好作用域 var xx = undefined
    其次 function的定义 function xx() {} 相当于 给 xx赋值了,因为具名了
    接着 function的定义 function() {}
    最后执行其他的语句
      

  11.   

    10L:
    谢谢指教!
    不过我只是针对7楼的例子稍作解释,似乎和你说的不是一个点,呵呵。
    -------------------
    8L:
    不实践,无真理。加句debugger,单步跟踪一下程序执行顺序吧:<script type='text/javascript'>
    debugger;//F11单步调试/*=================定义jeffstric函数体,在内存中开出一块空间写入{}块内容======================*/
    function jeffstric(){                   //step 1
      /*------------jeffstric函数内部结构---------------------*/
      //1.定义内部匿名函数体,赋值给声明的变量xx       
      var xx = function() {                        //step 2.1
        var y = '123' ;                               //step 2.9.1
        return y;                                     //step 2.9.2
      };
      
      //2.其他逐行解析的部分:
      alert('函数内部对话框1:  '+typeof om);        //step 2.2    
      alert('函数内部对话框2:  '+om);               //step 2.3
      var om = 'abc' ;                             //step 2.4
      alert('函数内部对话框3:  '+typeof om);        //step 2.5 
      alert('函数内部对话框4:  '+om);               //step 2.6 
      
      //3.对变量xx的不同调用方式
      alert('函数内部对话框5:  '+typeof xx);        //step 2.7 
      alert('函数内部对话框6:  '+xx);               //step 2.8
      var on=xx();/*执行xx函数,将处理结果赋值给on*/   //step 2.9
      alert('函数内部对话框7:  '+typeof on);        //step 2.10 
      alert('函数内部对话框8:  '+on);               //step 2.11 
      
      //4. 给出函数返回值
      return om+on;                               //step 2.12
    }
    /*===================end定义==================================*/alert(typeof jeffstric);              //step 2
    alert(jeffstric);                     //step 3
    alert('调用函数得到返回值:'+jeffstric()); //step 4//定义匿名函数,并用()立即调用执行
    (function(){                          //step 5
      var om = '我是一个函数,但我没名字' ;         //step 5.1
      alert(om);                                //step 5.2
    })();                                       //step 5.3   
    //定义匿名函数,但不执行。                     
    function(){                        //step 6
      var om = '我是一个函数,但我没名字' ;       
      alert(om);                                 
    }                                    
    </script>
      

  12.   

    应该是这样的,javascript并没有块级作用域一说,比如下面代码<script type='text/javascript'>
    var scope="gloable"
    function f(){
    alert(scope);
    var scope = "local";
    slert(scope);
    }
    </script>上边代码第一次弹出的是undefined,并非是gloable,代码与下边是等价的<script type='text/javascript'>
    var scope="gloable"
    function f(){
    var scope;
    alert(scope);
    var scope = "local";
    slert(scope);
    }
    </script>
      

  13.   


    真正学到东西了
    Csdn 人才辈出
      

  14.   

    理上网来老师 我觉得您是不是忽略了定义函数的优先执行原则,我认为顺序应该是这样的
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>执行顺序</title>
    </head>
    <script type='text/javascript'>
    //debugger;/*=================定义jeffstric函数体,在内存中开出一块空间写入{}块内容======================*/
    function jeffstric(){                              //1 定义jeffstric 为function                  
      /*------------jeffstric函数内部结构---------------------*/
      //1.定义内部匿名函数体,赋值给声明的变量xx       
      var xx = function() {                            //6.1定义xx为undefined  6.4定义匿名函数(‘理上网来’)  6.5定义xx为对该匿名函数的引用
        var y = '123' ;                                //6.13.1
        return y;                                      //6.13.2 返回'123'
      };                                               //
      
      //2.其他逐行解析的部分:
      alert('函数内部对话框1:  '+typeof om);            //6.6
      alert('函数内部对话框2:  '+om);                   //6.7
      var om = 'abc' ;                                 //6.2定义om为undefined  6.8定义om为‘abc’ 
      alert('函数内部对话框3:  '+typeof om);            //6.9
      alert('函数内部对话框4:  '+om);                   //6.10
      
      //3.对变量xx的不同调用方式
      alert('函数内部对话框5:  '+typeof xx);            //6.11 返回'理上网来老师'的类型
      alert('函数内部对话框6:  '+xx);                   //6.12 返回'理上网来老师'的内容
      var on=xx();/*执行xx函数,将处理结果赋值给on*/       //6.3定义on为undefined  6.13因为有() 所以'理上网来'的内容以函数的方式调用 6.14定义on为'123'
      alert('函数内部对话框7:  '+typeof on);             //6.15
      alert('函数内部对话框8:  '+on);                    //6.16
      
      //4. 给出函数返回值
      return om+on;                                     //6.17返回'abc123'
    }                                                  //
    /*===================end定义==================================*/alert(typeof jeffstric);                           //4   返回jeffstric的类型    
    alert(jeffstric);                                  //5   返回jeffstric的内容
                                                       /*谢谢10L独自流浪的指导:的xx + () 先找xx指向的内容,然后将内容按照函数的方式调用*/
    alert('调用函数得到返回值:'+jeffstric());             //6   因为有() 所以将jeffstric函数的内容以函数的方式调用 7输出//定义匿名函数,并用()立即调用执行
    (function(){                                        //2定义匿名函数(为了区分其他的匿名函数,取名,'老胡')  8有()将‘老胡’的内容以函数方式调用
      var om = '我是一个函数,但我没名字' ;                 //8.1
      alert(om);                                         //8.2
    })();                                       
    //定义匿名函数,但不执行。                     
    function(){                                        //3定义匿名函数('(独自流浪)')
      var om = '我是一个函数,但我没名字' ;             
      alert(om);                                 
    }                                    
    </script><body>
    </body>
    </html>
      

  15.   

    这我理解,因为JS是作用域链,当f()里已经预定义了scope时,就不会去上个作用域链寻找scope。
    另外我楼上的代码只能在firefox上运行,觉得很纳闷。
    最后,衷心地感谢各位的解答,让我学到颇多知识,不出意外的话,我打算今晚结帖。
      

  16.   

    发现CSDN真的是个很好的论坛,很谢谢(理上网来)(独自流浪)(老胡)老师,结贴了!