在编写 Ajax 方法的时候 经常会写上类似于这样的代码:

Ajax 代码:

var xmlHttp;//创建个XmlHttpRequeset对象function createXMLHttpRequest(){if(window.ActiveXObject){xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");}else if(window.XMLHttpRequest){xmlHttp = new XMLHttpRequest();}}//开始个请求function startRequest(){createXMLHttpRequest();xmlHttp.onreadystatechange = handlestatechange;xmlHttp.open("GET", "SimpleRespose.xml", true);xmlHttp.Send(null);}function handlestatechange(){if(xmlHttp.readyState == 4){//描述一种"已加载"状态;此时 响应已经被完全接收。if(xmlHttp.status == 200){//200表示成功收到 alert("The Server Replied with:" + xmlHttp.responseText)}}}

第一次阅读这段代码的时候 我就感到了一点点不对劲 但是说不出来什么地方不对劲。随着对Ajax代码的进一步了解 这种感觉时刻伴随着我。后来 我知道了这种感觉来自于什么地方。

看看 startRequest 函数。 发现 xmlHttp.onreadystatechange 指向了个函数 这个函数是在 xmlHttpRequest.readyState 发生改变的时候触发。 再来看 startRequest 函数 想象一下整个请求发送的步骤。现在 点击个按钮 触发了个 startRequest 函数。函数往下走 第一步是 createXmlHttpRequest() 它的作用是创建个 xmlHttpRequest 对象 当它完毕的时候 xmlHttpRequest.readyState 的值是 0( window.alert 跟踪得到的) 程序继续往下走 xmlHttp.onreadystatechange = handlestatechange 因为状态没有改变(xmlHttpRequest.readyState 的值是 0) 所以不触发函数 紧接着是 Open()和 Send() 那么 整个函数从头到尾都应该没有触发 handlestatechange 函数啊 但是为什么出来的结果是正确的呢?

后来我用 window.alert 跟踪 xmlHttp.readystate 的变化 发现于原来它运行的机制是这样的。首先创建个 xmlHttpRequest 的对象之后 xmlHttp.readyState 的值是 0 了 然后 xmlHttp.onreadystatechange = handlestatechange 没有运行。紧接着是 open() 这个函数发生了之后 xmlHttp.readyState 的值是 1 了 那么就会有个断点在 Open() 函数处断开 保留现场 紧接着又返回到 xmlHttp.onreadystatechange = handlestatechange 运行 然后再执行 Send() 函数 这个函数发生了之后 xmlHttp.readyState 的值是 2 了 接着又返回到 xmlHttp.onreadystatechange = handlestatechange 运行。以此类推。

浏览器因为不能真正地像面向对象那么编程 所以找了个折衷的办法 但是这个办法看起来不伦不类 想了半天 再跟个同学一起讨论 才得出这样的个结果。

onreadystatechange:设置为指向 handlestatechange的函数的指针(比较难理解些)

函数是具有执行特定功能的子程序 编译后 它的执行代码分配在代码段 而其参数及变量则在堆栈段 因而主程序调用函数时 实际上就是将程序执行地址转移为函数在代码段的入口地址去执行 即每个函数都有个在代码段的确定入口地址 依此程序执行 当遇到返回指令时(表示该程序结束) 程序便返回到该函数调用者的断点程序处 又继续执行 既然函数有确定的入口地址(实际上函数名就代表了它的入口地址) 因而可以用指针指向它 这个指针又称为函数指针。

原文地址:http://blog.chinaunix.net/uid-20730110-id-1883890.html