<!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');
}同样都是定义式的函数语句,为什么他们不会被优先执行?
这种定义模式实际上是定义一个匿名函数,再将函数的引用指向hello所以函数确实定义了,但是在解析这一行之前,你无法调用。
当需要判断一个变量是否为 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 在执行前会进行类似"预编译"的操作,而且先预定义变量再预定义函数。
tem相当于一个函数指针,指向下面的函数调用。
程序的实际执行顺序:
第一段语句执行:
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
按照
理论A:“
JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。而且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行。函数定义执行完后,才会按顺序执行其他
”来说,定义的函数会被优先执行,但是下面的例子
function () {
alert(om); // 显示 undefined
var om = 'abc' ;
alert(om); // 显示 abc
}
程序的实际执行顺序应该是
var om='abc';
alert(om);
alert(om);
那么应该都是显示abc abc
但结果却是 显示 undefined 显示 abc
是不是说理论A错误的?
对于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不知我的解释是否有误?
你理解偏了。给你翻译一下你的理论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行:“你明白了?”
另外呢,我还有个疑问:理论A“
JavaScript执行引擎并非一行一行地分析和执行程序,而是一段一段地分析执行的。而且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行。
”
中你仅解释了1:"是一段一段地分析执行的" 还没解释道2:"定义式的函数语句会被提取出来优先执行。"
我对2的理解是:
“
对于function函数,优先解释,解释完毕后再解释var的定义语句,但仅仅是预定义(即只是把该变量预定义为undefined)
”
不知我的解释是否正确,恳请指正!
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”
关于你2的理解,其实有点错误那个匿名函数其实已经在内存了,只是没有具名(function () {})
function xx() {}
都会预定义2个函数,一个只不过有明确变量指向,一个没有变量指向你可以想想xx()的理解是xx + () 先找xx指向的内容,然后将内容按照函数的方式调用那么就会理解
function xx(){}
xx();
var xx = function() {};其实 先找var 定义的变量,定义好作用域 var xx = undefined
其次 function的定义 function xx() {} 相当于 给 xx赋值了,因为具名了
接着 function的定义 function() {}
最后执行其他的语句
谢谢指教!
不过我只是针对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>
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>
真正学到东西了
Csdn 人才辈出
<!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>
另外我楼上的代码只能在firefox上运行,觉得很纳闷。
最后,衷心地感谢各位的解答,让我学到颇多知识,不出意外的话,我打算今晚结帖。