<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>幼学笔记 &#187; 回调</title>
	<atom:link href="http://www.oncoding.cn/tag/callback/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.oncoding.cn</link>
	<description>追寻简单生活</description>
	<lastBuildDate>Tue, 13 Jul 2010 03:47:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>JavaScript程序执行顺序问题总结</title>
		<link>http://www.oncoding.cn/2009/javascript_execution_sequence/</link>
		<comments>http://www.oncoding.cn/2009/javascript_execution_sequence/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 14:47:48 +0000</pubDate>
		<dc:creator>j5726</dc:creator>
				<category><![CDATA[前端]]></category>
		<category><![CDATA[地图]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[回调]]></category>
		<category><![CDATA[执行顺序]]></category>

		<guid isPermaLink="false">http://www.oncoding.cn/?p=304</guid>
		<description><![CDATA[好记星不如烂笔头，适时的总结梳理知识让人更轻松愉快。今天总结下学习和开发中遇到的JavaScript执行顺序的问题，今天挖个坑，以后会慢慢填，也希望抛砖引玉，能学到更多的东西。 顺序可能比较乱，写多了再整理，有些术语可能运用也不恰当，欢迎批评指正。以下使用的示例程序都经过了本人的实际验证，兼容各大浏览器。OK，步入正题。 1. 变量的声明和引用 变量必须先声明后引用，这个大家是都知道的，但还是要说说，因为后面要说到一个相关的问题。 alert(myStr); // 弹出&#34;undefined&#34;; var myStr = &#34;Hello World!&#34;; alert(myStr); // 弹出&#34;Hello World&#34;; 2. 函数的声明和调用 JavaScript是一种描述型脚本语言，由浏览器进行动态的解析与执行。函数的定义方式大体有以下两种，浏览器对于不同的方式有不同的解析顺序。 //“定义式”函数定义 function Fn1(){ alert(&#34;Hello World!&#34;); } //“赋值式”函数定义 var Fn2 = function(){ alert(&#34;Hello wild!&#34;); } 页面加载过程中，浏览器会对页面上或载入的每个js代码块(或文件)进行扫描，如果遇到定义式函数，则进行预处理(类似于C等的编译)，处理完成之后再开始由上至下执行；遇到赋值式函数，则只是将函数赋给一个变量，不进行预处理(类似1中变量必须先定义后引用的原则)，待调用到的时候才进行处理。下面举个简单的例子： //“定义式”函数定义 Fn1(); function Fn1(){ alert(&#34;Hello World!&#34;); } 正常执行，弹出“Hello World!”，浏览器对Fn1进行了预处理，再从Fn1();开始执行。 //“赋值式”函数定义 Fn2(); var Fn2 = function(){ alert(&#34;Hello wild!&#34;); } Firebug报错：Fn2 is [...]]]></description>
			<content:encoded><![CDATA[<p>好记星不如烂笔头，适时的总结梳理知识让人更轻松愉快。今天总结下学习和开发中遇到的JavaScript执行顺序的问题，今天挖个坑，以后会慢慢填，也希望抛砖引玉，能学到更多的东西。</p>
<p>顺序可能比较乱，写多了再整理，有些术语可能运用也不恰当，欢迎批评指正。以下使用的示例程序都经过了本人的实际验证，兼容各大浏览器。OK，步入正题。</p>
<h3 id="id1">1. 变量的声明和引用</h3>
<p>变量必须先声明后引用，这个大家是都知道的，但还是要说说，因为后面要说到一个相关的问题。</p>
<pre class="brush: jscript;">
alert(myStr); // 弹出&quot;undefined&quot;;
var myStr = &quot;Hello World!&quot;;
alert(myStr); // 弹出&quot;Hello World&quot;;
</pre>
<h3 id="id2">2. 函数的声明和调用</h3>
<p><span id="more-304"></span></p>
<p>JavaScript是一种描述型脚本语言，由浏览器进行动态的解析与执行。函数的定义方式大体有以下两种，浏览器对于不同的方式有不同的解析顺序。</p>
<pre class="brush: jscript;">
//“定义式”函数定义
function Fn1(){
    alert(&quot;Hello World!&quot;);
}
//“赋值式”函数定义
var Fn2 = function(){
    alert(&quot;Hello wild!&quot;);
}
</pre>
<p>页面加载过程中，浏览器会对页面上或载入的每个js代码块(或文件)进行扫描，如果遇到定义式函数，则进行预处理(类似于C等的编译)，处理完成之后再开始由上至下执行；遇到赋值式函数，则只是将函数赋给一个变量，不进行预处理(类似<a href="#id1">1中变量必须先定义后引用的原则</a>)，待调用到的时候才进行处理。下面举个简单的例子：</p>
<pre class="brush: jscript;">
//“定义式”函数定义
Fn1();
function Fn1(){
    alert(&quot;Hello World!&quot;);
}
</pre>
<p>正常执行，弹出“Hello World!”，浏览器对Fn1进行了预处理，再从Fn1();开始执行。</p>
<pre class="brush: jscript;">
//“赋值式”函数定义
Fn2();
var Fn2 = function(){
    alert(&quot;Hello wild!&quot;);
}
</pre>
<p>Firebug报错：Fn2 is not a function，浏览器未对Fn2进行预处理，依序执行，所以报错Fn2未定义。</p>
<p>关于Javascript的“编译”和执行过程，射雕在<a href="http://lifesinger.org/blog/2009/01/javascript-run-mechanism/" target="_blank">《JavaScript运行机制浅探》</a>中有更深入的分析，推荐阅读。</p>
<h3>3. 代码块及js文件的处理</h3>
<p>“代码块”是指一对<script type="text/javascript"></script>标签包裹着的js代码，文件就是指文件啦，废话:D</p>
<p>浏览器对每个块或文件进行独立的扫描，然后对全局的代码进行顺序执行(<a href="#id2">2中讲到了</a>)。所以，在一个块(文件)中，函数可以在调用之后进行“定义式”定义；但在两个块中，定义函数所在的块必须在函数被调用的块之前。</p>
<p>很绕口，看例子好了：</p>
<pre class="brush: jscript;">
&lt;script type=&quot;text/javascript&quot;&gt;
    Fn();
&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    function Fn(){
        alert(&quot;Hello World!&quot;);
    }
&lt;/script&gt;
// 报错：Fn is notdefined，两个块换过来就对了
</pre>
<h3>4. 重复定义函数会覆盖前面的定义</h3>
<p>这和变量的重复定义是一样的，代码：</p>
<pre class="brush: jscript;">
function fn(){
    alert(1);
}
function fn(){
    alert(2);
}
fn();
// 弹出：“2”
</pre>
<p>如果是这样呢：</p>
<pre class="brush: jscript;">
fn();
function fn(){
    alert(1);
}
function fn(){
    alert(2);
}
// 还是弹出：“2”
</pre>
<p>还是弹出“2”，为什么？<a href="#id2">2都讲了好吧&#8230;</a></p>
<h3 id="id5">5. body的onload函数与body内部函数的执行</h3>
<p>body内部的函数会先于onload的函数执行，测试代码：</p>
<pre class="brush: jscript;">
//html head...
&lt;script type=&quot;text/javascript&quot;&gt;
function fnOnLoad(){
    alert(&quot;I am outside the Wall!&quot;);
}
&lt;/script&gt;
&lt;body onload=&quot;fnOnLoad();&quot;&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    alert(&quot;I am inside the Wall..&quot;);
&lt;/script&gt;
&lt;/body&gt;
//先弹出“I am inside the Wall..”;
//后弹出“I am outside the Wall!”
</pre>
<p>body的onload事件触发条件是body内容加载完成，而body中的js代码会在这一事件触发之前运行(为什么呢?<a href="#id6">6告诉你..</a>)</p>
<h3 id="id6">6. JavaScript是多线程or单线程？</h3>
<p>严格来说，JavaScript是没有多线程概念的，所有的程序都是“单线程”依次执行的。</p>
<p>举个不太恰当的例子：</p>
<pre class="brush: jscript;">
function fn1(){
    var sum = 0;
    for(var ind=0; ind&lt;1000; ind++) {
        sum += ind;
    }
    alert(&quot;答案是&quot;+sum);
}
function fn2(){
    alert(&quot;早知道了，我就是不说&quot;);
}
fn1();
fn2();
//先弹出：“答案是499500”，
//后弹出：“早知道了，我就是不说”
</pre>
<p>那你肯定要问：那延时执行、Ajax异步加载，不是多线程的吗？没错，下面这样的程序确实看起来像“多线程”：</p>
<pre class="brush: jscript;">
function fn1(){
    setTimeout(function(){
        alert(&quot;我先调用&quot;)
    },1000);
}
function fn2(){
    alert(&quot;我后调用&quot;);
}
fn1();
fn2();
// 先弹出：“我后调用”，
// 1秒后弹出：“我先调用”
</pre>
<p>看上去，fn2()和延时程序是分两个过程再走，但其实，这是JavaScript中的“回调”机制在起作用，类似于操作系统中的“中断和响应” —— 延时程序设置一个“中断”，然后执行fn2()，待1000毫秒时间到后，再回调执行fn1()。</p>
<p>同样，<a href="#id5">5中body的onload事件</a>调用的函数，也是利用了回调机制——body加载完成之后，回调执行fnOnLoad()函数。</p>
<p>Ajax请求中的数据处理函数也是一样的道理。</p>
<p>关于JavaScript线程问题的更深入讨论，看这篇 <a href="http://blog.csdn.net/turkeyzhou/archive/2008/08/07/2784934.aspx" target="_blank">javascript中的线程之我见</a>，以及infoQ上的 <a href="http://www.infoq.com/cn/articles/js_multithread;jsessionid=15A6283AD9008B0AFAB542C42A10B81F" target="_blank">JavaScript多线程编程简介</a>。</p>
<p>困了，再说一下回调函数吧。</p>
<h3>7. 回调函数</h3>
<p>回调函数是干嘛用的？就是回调执行的函数嘛，又废话:D</p>
<p>如6所说，最常见的回调就是onclick、onmouseover、onmousedown、onload等等浏览器事件的调用函数；还有Ajax异步请求数据的处理函数；setTimeOut延时执行、setInterval循环执行的函数等。</p>
<p>干脆我们写一个纯粹的回调函数玩：</p>
<pre class="brush: jscript;">
function onBack(num){
    alert(&quot;姗姗我来迟了&quot;);
    // 执行num个耳光
}
function dating(hours, callBack){
    var SP= 0; // SP,愤怒值
    //女猪脚在雪里站了hours个钟头
    //循环开始..
    SP ++;
    //循环结束...
    callBack(SP);
}

dating(1, onBack);
</pre>
<p>dating运行完之后再执行回调函数onBack —— 约会结束了，暴风骤雨开始了。</p>
<p>今天先写到这里，一些更深入的东西还有待整理，更多的东西还需要继续学习，欢迎批改补充，欢迎指点迷津。</p>
<p style="text-align: right;"><a href="http://www.oncoding.cn/2009/javascript_execution_sequence/">幼学笔记</a>原创内容，根据<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">CC协议</a>发布，欢迎具名转载。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.oncoding.cn/2009/javascript_execution_sequence/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
