??xml version="1.0" encoding="utf-8" standalone="yes"?> 代码很简单,定义两个同名的函数myFnQ然后在不同的地方调用该函数Q但执行的结果却Zh意料, 下来我们l箋试Q看W二D|试代码: q里可能大家认ؓ输出l果跟上ơ的一P错了Q这ơ第一ơ输出Fn1Q第二次输出Fn2.l箋试Q?br />试代码三: q次输出的结果是Fn1,Fn2. 试代码四: 输出Fn1,Fn2. 试代码五: 输出Fn1, Fn1 试代码六: 输出l果是Fn2,Fn1,Fn1 试代码七: 输出Fn1,而不是未定义的函?/p>
试代码八: 则提C缺对象,也就是函数没定义?/p>
试代码九: 则提C缺对象,也就是函数没定义?/p>
从上面的试例子中,我们可以发现javascripthcM“预编?#8221;Q或者有人称?#8220;预解?#8221;Q的 特点Q从q点看,javascript实有点像传l的~译型语aQ比如c,c++{。但javascript跟这U语a?/p>
有根本上的区别,在javascript中,q种预编译的Ҏƈ不是Ҏ有的js代码q行的,从上面的试?/p>
子中Q我们可以发玎ͼ把myFn的定义分别放C同的script块中q行调用的时候,׃提示对象未定?/p>
Q从q点看,javascript?#8220;预编?#8221;Ҏ只是对属于同一?卛_含在同一?lt;script></script>??/p>
的代码有效?br /> 其实Q在javascript的执行过E中Qjs引擎扫描每一script块的代码Q把里面的各U函数定义都抽出 来进?#8220;预编?#8221;Q注意,q里说的是函数定义而不是函数赋|或者说是定义式的函敎ͼ那什么是?/p>
义式的函数呢Q如下的形式是Q?br />function myFn(){ U结果也很清楚了?br />试代码一Q?br />首先js引擎扫描该script块中的函数定义(注意q个时候还没开始执行代码)Q发现有定义式函?/p>
function myFn(){}有两处,׃名字是一LQ编译后合成了一个myFn函数Q后面的定义覆盖了前?/p>
的定义,所以在函数执行之前只有一个编译的函数myFn,q且其定义是后面的那个,因此真正到执行代 码的时候,也就是第一ơ调用myFn(),输出的当然是Fn2,W二ơ执行myFn同样输出Fn2. 试代码二: 后的myFn函数q没有被W二块的myFn覆盖Q因此第一个执行myFn输出的是Fn1,同样W二块输出的是Fn2. 值给一个变量,赋D句的执行时机晚于~译时刻Q定义式函数是在执行语句之前完成了的,而赋?/p>
语句要到执行的时候才q行。通过q样的说明,可以很清楚的解?br />试代码七ؓ什么不是提C函数未定义Q而是输出Fn1,而测试代码八则提C对象未定义的原因了Q因?/p>
试代码在执行myFn之前Q已l优先执行了定义式函数的~译Q也是_myFn已经是一个定义了的函 敎ͼ因此到执行时候当然能够正常执行,而测试代码ƈ没有定义式函敎ͼ在执行代码之前是没有M?/p>
l编译好的函数定义的Q而到执行myFn()的时候当然提C函数没定义Q接下来才执行函数赋|把一?/p>
函数赋值给一个myFn变量Q这时候如果调用myFn可以了?/p>
两次输出的结果都是Fn2Q而不是我们认为的W一ơ输出Fn1Q第二次输出Fn2。具体原因这里先不说Q接
试代码二:
//Code goes here
};
~译完成后,根据script块中的语句从上到下,从左到右q行执行。根据这L解释Q上面输出的?/p>
׃javascript的块~译Ҏ,因此分成在不同的块中的代码是分开~译的,所以第一个script块编?/p>
需要重Ҏ出的是var myFn = function(){};不是定义式函数声明,而是赋D句,把一个函数对象赋
]]>
JavaScriptE序执行序问题ȝ
好记星不如烂W头Q适时的ȝ梳理知识让h更轻松愉快。今天ȝ下学习和开发中遇到?/span>JavaScript执行序的问题,今天挖个坑,以后会慢慢填Q也希望抛砖引玉Q能学到更多的东ѝ?/span>
序可能比较乱,写多了再整理Q有些术语可能运用也不恰当,Ƣ迎批评指正。以下用的CZE序都经q了本h的实际验证,兼容各大览器?/span>OKQ步入正题?/span>
1. 变量的声明和引用
变量必须先声明后引用Q这个大家是都知道的Q但q是要说_因ؓ后面要说C个相关的问题?/span>
1 2 3 |
alert(myStr); // 弹出"undefined"; var myStr = "Hello World!"; alert(myStr); // 弹出"Hello World"; |
2. 函数的声明和调用
JavaScript是一U描q型脚本语言Q由览器进行动态的解析与执行。函数的定义方式大体有以下两U,览器对于不同的方式有不同的解析序?/span>
1 2 3 4 5 6 7 8 |
//“定义?#8221;函数定义 function Fn1(){ alert("Hello World!"); } //“赋值式”函数定义 var Fn2 = function(){ alert("Hello wild!"); } |
面加蝲q程中,览器会寚w面上或蝲入的每个js代码?/span>(或文?/span>)q行扫描Q如果遇到定义式函数Q则q行预处?/span>(cM?/span>C{的~译)Q处理完成之后再开始由上至下执行;遇到赋值式函数Q则只是函数赋l一个变量,不进行预处理(cM1中变量必d定义后引用的原则)Q待调用到的时候才q行处理。下面D个简单的例子Q?/span>
1 2 3 4 5 |
//“定义?#8221;函数定义 Fn1(); function Fn1(){ alert("Hello World!"); } |
正常执行Q弹?/span>“Hello World!”Q浏览器?/span>Fn1q行了预处理Q再?/span>Fn1();开始执行?/span>
1 2 3 4 5 |
//“赋值式”函数定义 Fn2(); var Fn2 = function(){ alert("Hello wild!"); } |
Firebug报错Q?/span>Fn2 is not a functionQ浏览器未对Fn2q行预处理,依序执行Q所以报?/span>Fn2未定义?/span>
3. 代码块及js文g的处?/span>
“代码?/span>”是指一?/span><script type=”text/javascript”></script>标签包裹着?/span>js代码Q文件就是指文g啦,废话:D
览器对每个块或文gq行独立的扫描,然后对全局的代码进行顺序执?/span>(2中讲C)。所以,在一个块(文g)中,函数可以在调用之后进?/span>“定义?/span>”定义Q但在两个块中,定义函数所在的块必d函数被调用的块之前?/span>
很绕口,看例子好了:
1 2 3 4 5 6 7 8 9 |
<script type="text/javascript"> Fn(); </script> <script type="text/javascript"> function Fn(){ alert("Hello World!"); } </script> // 报错QFn is notdefinedQ两个块换过来就对了 |
4. 重复定义函数会覆盖前面的定义
q和变量的重复定义是一LQ代码:
1 2 3 4 5 6 7 8 |
function fn(){ alert(1); } function fn(){ alert(2); } fn(); // 弹出Q?#8220;2” |
如果是这样呢Q?/span>
1 2 3 4 5 6 7 8 |
fn(); function fn(){ alert(1); } function fn(){ alert(2); } // q是弹出Q?#8220;2” |
q是弹出“2”Qؓ什么?2都讲了好?/span>…
5. body?/span>onload函数?/span>body内部函数的执?/span>
body内部的函C先于onload的函数执行,试代码Q?/span>
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//html head... <script type="text/javascript"> function fnOnLoad(){ alert("I am outside the Wall!"); } </script> <body onload="fnOnLoad();"> <script type="text/javascript"> alert("I am inside the Wall.."); </script> </body> //先弹?#8220;I am inside the Wall..”; //后弹?#8220;I am outside the Wall!” |
body?/span>onload事g触发条g?/span>body内容加蝲完成Q?/span>body中的js代码会在q一事g触发之前q行(Z么呢?6告诉?/span>..)
6. JavaScript是多U程or单线E?
严格来说Q?/span>JavaScript是没有多U程概念的,所有的E序都是“单线E?/span>”依次执行的?/span>
举个不太恰当的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function fn1(){ var sum = 0; for(var ind=0; ind<1000; ind++) { sum += ind; } alert("{案?+sum); } function fn2(){ alert("早知道了Q我是不说"); } fn1(); fn2(); //先弹出:“{案?99500”Q? //后弹出:“早知道了Q我是不说” |
那你肯定要问Q那延时执行?/span>Ajax异步加蝲Q不是多U程的吗Q没错,下面q样的程序确实看h?/span>“多线E?/span>”Q?/span>
1 2 3 4 5 6 7 8 9 10 11 12 |
function fn1(){ setTimeout(function(){ alert("我先调用") },1000); } function fn2(){ alert("我后调用"); } fn1(); fn2(); // 先弹出:“我后调用”Q? // 1U后弹出Q?#8220;我先调用” |
看上去,fn2()和g时程序是分两个过E再赎ͼ但其实,q是JavaScript中的“回调”机制在v作用Q类g操作pȝ中的“中断和响?/span>” —— 延时E序讄一?/span>“中断”Q然后执?/span>fn2()Q待1000毫秒旉到后Q再回调执行fn1()?/span>
同样Q?/span>5?/span>body?/span>onload事g调用的函敎ͼ也是利用了回调机?/span>——body加蝲完成之后Q回调执?/span>fnOnLoad()函数?/span>
Ajaxh中的数据处理函数也是一L道理?/span>
关于JavaScriptU程问题的更深入讨论Q看q篇 javascript中的U程之我?/span>Q以?/span>infoQ上的 JavaScript多线E编E简?/span>?/span>
CQ再说一下回调函数吧?/span>
7. 回调函数
回调函数是干嘛用的?是回调执行的函数嘛Q又废话:D
?/span>6所_最常见的回调就?/span>onclick?/span>onmouseover?/span>onmousedown?/span>onload{等览器事件的调用函数Q还?/span>Ajax异步h数据的处理函敎ͼsetTimeOut延时执行?/span>setInterval循环执行的函数等?/span>
q脆我们写一个纯_的回调函数玩:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function onBack(num){ alert("姗姗我来q了"); // 执行num个耛_ } function dating(hours, callBack){ var SP= 0; // SP,愤怒? //女猪脚在雪里站了hours个钟? //循环开?. SP ++; //循环l束... callBack(SP); } dating(1, onBack); |
datingq行完之后再执行回调函数onBack —— U会l束了,暴风骤雨开始了?/span>
今天先写到这里,一些更深入的东西还有待整理Q更多的东西q需要l学习,Ƣ迎Ҏ补充Q欢q指点迷z?/span>