jQuery原理模拟代码

转载自:点击打开链接

JQuery 原理

 

 

jQuery 的原型关系图

  

jQuery 原理的模拟代码 -1 核心部分

 

jQuery 原理的模拟代码 -2 数据部分

 

jQuery 原理的模拟代码 -3 事件处理

 

jQuery 原理的模拟代码 -4 重要的扩展函数 extend

 

jQuery 原理的模拟代码 -5 Ajax

 

 

 

jQuery 的原型关系图

 

回到目录

jQuery 原理的模拟代码 -1 核心部分

 

最近又看了一下 jQuery 1.4.2, 为了便于理解,将 jQuery 的核心使用比较简单的代码模拟一下。方便学习。

 

核心部分实现了两种选择器,使用 id 和标记名,还可以提供 css 的设置,以及 text 的设置。

 

[c-sharp]  view plain copy
  1.   1 // # 表示在 jQuery 1.4.2 中对应的行数  
  2.   2   
  3.   3 // 定义变量 undefined 方便使用  
  4.   4 var undefined = undefined;  
  5.   5   
  6.   6 // jQuery 是一个函数,其实调用 jQuery.fn.init 创建对象  
  7.   7 var $ = jQuery = window.$ = window.jQuery               // #19  
  8.   8             = function (selector, context) {  
  9.   9                 return new jQuery.fn.init(selector, context);  
  10.  10             },  
  11.  11   
  12.  12 // 定义 toString 变量引用 Object 原型的 toString  
  13.  13 toString = Object.prototype.toString,  
  14.  14   
  15.  15 // 用来检查是否是一个 id  
  16.  16 idExpr = /^#([/w-]+)$/;  
  17.  17   
  18.  18 // 设置 jQuery 的原型对象, 用于所有 jQuery 对象共享  
  19.  19 jQuery.fn = jQuery.prototype = {                        // #74  
  20.  20   
  21.  21     length: 0,                                          // #190  
  22.  22   
  23.  23     jquery: "1.4.2",                                    // # 187  
  24.  24   
  25.  25     // 这是一个示例,仅仅提供两种选择方式:id 和标记名  
  26.  26     init: function (selector, context) {                // #75  
  27.  27   
  28.  28         // Handle HTML strings  
  29.  29         if (typeof selector === "string") {  
  30.  30             // Are we dealing with HTML string or an ID?  
  31.  31             match = idExpr.exec(selector);  
  32.  32   
  33.  33             // Verify a match, and that no context was specified for #id  
  34.  34             if (match && match[1]) {  
  35.  35                 var elem = document.getElementById(match[1]);  
  36.  36                 if (elem) {  
  37.  37                     this.length = 1;  
  38.  38                     this[0] = elem;  
  39.  39                 }  
  40.  40             }  
  41.  41             else {  
  42.  42                 // 直接使用标记名  
  43.  43                 var nodes = document.getElementsByTagName(selector);  
  44.  44                 for (var l = nodes.length, j = 0; j < l; j++) {  
  45.  45                     this[j] = nodes[j];  
  46.  46                 }  
  47.  47                 this.length = nodes.length;  
  48.  48             }  
  49.  49   
  50.  50             this.context = document;  
  51.  51             this.selector = selector;  
  52.  52   
  53.  53             return this;  
  54.  54         }  
  55.  55     },  
  56.  56   
  57.  57     // 代表的 DOM 对象的个数  
  58.  58     size: function () {                                 // #193  
  59.  59         return this.length;  
  60.  60     },  
  61.  61   
  62.  62     // 用来设置 css 样式  
  63.  63     css: function (name, value) {                       // #4564  
  64.  64         this.each(  
  65.  65                     function (name, value) {  
  66.  66                         this.style[name] = value;  
  67.  67                     },  
  68.  68                     arguments       // 实际的参数以数组的形式传递  
  69.  69                     );  
  70.  70         return this;  
  71.  71     },  
  72.  72   
  73.  73     // 用来设置文本内容  
  74.  74     text: function (val) {                              // #3995  
  75.  75         if (val) {  
  76.  76             this.each(function () {  
  77.  77                 this.innerHTML = val;  
  78.  78             },  
  79.  79                     arguments       // 实际的参数以数组的形式传递  
  80.  80                     )  
  81.  81         }  
  82.  82         return this;  
  83.  83     },  
  84.  84   
  85.  85     // 用来对所有的 DOM 对象进行操作  
  86.  86     // callback 自定义的回调函数  
  87.  87     // args 自定义的参数  
  88.  88     each: function (callback, args) {                   // #244  
  89.  89         return jQuery.each(this, callback, args);  
  90.  90     }  
  91.  91   
  92.  92 }  
  93.  93   
  94.  94 // init 函数的原型也就是 jQuery 的原型  
  95.  95 jQuery.fn.init.prototype = jQuery.prototype;            // #303  
  96.  96   
  97.  97 // 用来遍历 jQuery 对象中包含的元素  
  98.  98 jQuery.each = function (object, callback, args) {       // #550  
  99.  99   
  100. 100     var i = 0, length = object.length;  
  101. 101   
  102. 102     // 没有提供参数  
  103. 103     if (args === undefined) {  
  104. 104   
  105. 105         for (var value = object[0];  
  106. 106                     i < length && callback.call(value, i, value) !== false;  
  107. 107                      value = object[++i])  
  108. 108         { }  
  109. 109     }  
  110. 110   
  111. 111     else {  
  112. 112         for (; i < length; ) {  
  113. 113             if (callback.apply(object[i++], args) === false) {  
  114. 114                 break;  
  115. 115             }  
  116. 116         }  
  117. 117     }  
  118. 118 }  
  119. 119   

 

在 jQuery 中, jQuery 对象实际上是一个仿数组的对象,代表通过选择器得到的所有 DOM 对象的集合,它像数组一样有 length 属性,表示代表的 DOM 对象的个数,还可以通过下标进行遍历。

 

95 行的 jQuery.each 是 jQuery 中用来遍历这个仿数组,对其中的每个元素进行遍历处理的基本方法,callback 表示处理这个 DOM 对象的函数。通常情况下,我们并不使用这个方法,而是使用 jQuery 对象的 each 方法进行遍历。jQuery 对象的 css 和 text 方法在内部实际上使用 jQuery 对象的 each 方法对所选择的元素进行处理。

 

这些函数及对象的关系见:jQuery 原型关系图

 

下面的脚本使用这个脚本库。

 

 

[c-sharp]  view plain copy
  1. 1  // 原型操作  
  2. 2  $("h1").text("Hello, world.").css("color""green");  
  3. 3   

 

 

回到目录

jQuery 原理的模拟代码 -2 数据部分

 在 jQuery 中,可以对每一个 DOM 对象保存私有的数据。

 

这个数据当然要通过属性来进行存取,但是,有多个属性怎么办呢?,要定义多个属性吗?,属性的名字叫什么呢?会不会与其他的属性有冲突呢?

 

在 jQuery 中,针对 DOM  对象扩展的私有数据可以用一个对象来表示,多个数据就使用这个对象的多个属性来表示。为了能够通过 DOM 对象找到这个扩展数据对象,而不会与其他现有的属性冲突,在 jQuery 中通过 expando 这个常量表示扩展对象的属性名,这个 expando 的值是计算出来的。而这个属性的值就是用来找到扩展对象的键值。

 

例如,我们可以定义 expando 的值为 "jQuery1234" ,那么,我们可以为每个 DOM 对象增加这个名为  "jQuery1234" 的属性,这个属性的值可以是一个键,例如为 1000。

 

在 jQuery 对象上的 cache 用来保存所有对象扩展的对象,这个对象可以看作一个字典,属性名就是键值,所对应的值就是扩展数据对象。

 

也就是说,在 jQuery 对象的 cache 上,将会有一个 1000 的成员,这个成员引用的对象就是 1000 号 DOM 对象的私有扩展对象。1000 号成员的私有数据将被存在在这个对象上。

 

当一个 DOM 对象需要取得扩展数据的时候,首先通过对象的 expando 属性取得一个键值,然后通过这个键值到 jQuery.cache 中取得自己的扩展对象,然后在扩展对象上读写数据。

 

 

[c-sharp]  view plain copy
  1.   1 /// <reference path="jQuery-core.js" />  
  2.   2   
  3.   3 // 常用方法  
  4.   4 function now() {  
  5.   5     return (new Date).getTime();  
  6.   6 }  
  7.   7   
  8.   8 // 扩充数据的属性名,动态生成,避免与已有的属性冲突  
  9.   9 var expando = "jQuery" + now(), uuid = 0, windowData = {};  
  10.  10 jQuery.cache = {};  
  11.  11 jQuery.expando = expando;  
  12.  12   
  13.  13 // 数据管理,可以针对 DOM 对象保存私有的数据,可以读取保存的数据  
  14.  14 jQuery.fn.data = function (key, value) {  
  15.  15   
  16.  16     // 读取  
  17.  17     if (value === undefined) {  
  18.  18         return jQuery.data(this[0], key);  
  19.  19     }  
  20.  20     else {  // 设置  
  21.  21   
  22.  22         this.each(  
  23.  23                     function () {  
  24.  24                         jQuery.data(this, key, value);  
  25.  25                     }  
  26.  26                     );  
  27.  27     }  
  28.  28 }  
  29.  29 // 移除数据,删除保存在对象上的数据  
  30.  30 jQuery.fn.removeData = function (key) {  
  31.  31     return this.each(function () {  
  32.  32         jQuery.removeData(this, key);  
  33.  33     })  
  34.  34 }  
  35.  35   
  36.  36   
  37.  37 // 为元素保存数据  
  38.  38 jQuery.data = function (elem, name, data) {     // #1001  
  39.  39   
  40.  40     // 取得元素保存数据的键值  
  41.  41     var id = elem[expando], cache = jQuery.cache, thisCache;  
  42.  42   
  43.  43     // 没有 id 的情况下,无法取值  
  44.  44     if (!id && typeof name === "string" && data === undefined) {  
  45.  45         return null;  
  46.  46     }  
  47.  47   
  48.  48     // Compute a unique ID for the element  
  49.  49     // 为元素计算一个唯一的键值  
  50.  50     if (!id) {  
  51.  51         id = ++uuid;  
  52.  52     }  
  53.  53   
  54.  54     // 如果没有保存过  
  55.  55     if (!cache[id]) {  
  56.  56         elem[expando] = id;     // 在元素上保存键值  
  57.  57         cache[id] = {};         // 在 cache 上创建一个对象保存元素对应的值  
  58.  58     }  
  59.  59   
  60.  60     // 取得此元素的数据对象  
  61.  61     thisCache = cache[id];  
  62.  62   
  63.  63     // Prevent overriding the named cache with undefined values  
  64.  64     // 保存值  
  65.  65     if (data !== undefined) {  
  66.  66         thisCache[name] = data;  
  67.  67     }  
  68.  68   
  69.  69     // 返回对应的值  
  70.  70     return typeof name === "string" ? thisCache[name] : thisCache;  
  71.  71   
  72.  72 }  
  73.  73   
  74.  74 // 删除保存的数据  
  75.  75 jQuery.removeData = function (elem, name) {     // #1042  
  76.  76   
  77.  77     var id = elem[expando], cache = jQuery.cache, thisCache = cache[id];  
  78.  78   
  79.  79     // If we want to remove a specific section of the element's data  
  80.  80     if (name) {  
  81.  81         if (thisCache) {  
  82.  82             // Remove the section of cache data  
  83.  83             delete thisCache[name];  
  84.  84   
  85.  85             // If we've removed all the data, remove the element's cache  
  86.  86             if (jQuery.isEmptyObject(thisCache)) {  
  87.  87                 jQuery.removeData(elem);  
  88.  88             }  
  89.  89         }  
  90.  90   
  91.  91         // Otherwise, we want to remove all of the element's data  
  92.  92     } else {  
  93.  93   
  94.  94         delete elem[jQuery.expando];  
  95.  95   
  96.  96         // Completely remove the data cache  
  97.  97         delete cache[id];  
  98.  98     }  
  99.  99 }  
  100. 100   
  101. 101 // 检查对象是否是空的  
  102. 102 jQuery.isEmptyObject = function (obj) {  
  103. 103     // 遍历元素的属性,只有要属性就返回假,否则返回真  
  104. 104     for (var name in obj) {  
  105. 105         return false;  
  106. 106     }  
  107. 107     return true;  
  108. 108   
  109. 109 }  
  110. 110   
  111. 111 // toString 是 jQuery 中定义的一个变量 #68  
  112. 112 // hasOwnProperty                    #69  
  113. 113   
  114. 114 // 检查是否是一个函数  
  115. 115 jQuery.isFunction = function (obj) {  
  116. 116     return toString.call(obj) === "[object Function]";  
  117. 117 }  
  118. 118   
  119. 119 // 检查是否为一个数组  
  120. 120 jQuery.isArray = function( obj ) {  
  121. 121         return toString.call(obj) === "[object Array]";  
  122. 122     }  
  123. 123   
  124. 124 // 是否是纯粹的 js 对象,而不是 DOM 对象,或者 window 对象  
  125. 125 jQuery.isPlainObject = function( obj ) {  
  126. 126         // Must be an Object.  
  127. 127         // Because of IE, we also have to check the presence of the constructor property.  
  128. 128         // Make sure that DOM nodes and window objects don't pass through, as well  
  129. 129         if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {  
  130. 130             return false;  
  131. 131         }  
  132. 132           
  133. 133         // Not own constructor property must be Object  
  134. 134         if ( obj.constructor  
  135. 135             && !hasOwnProperty.call(obj, "constructor")  
  136. 136             && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {  
  137. 137             return false;  
  138. 138         }  
  139. 139           
  140. 140         // Own properties are enumerated firstly, so to speed up,  
  141. 141         // if last one is own, then all properties are own.  
  142. 142       
  143. 143         var key;  
  144. 144         for ( key in obj ) {}  
  145. 145           
  146. 146         return key === undefined || hasOwnProperty.call( obj, key );  
  147. 147     }  
  148. 148   

 

下面的脚本可以保存或者读取对象的扩展数据。

 

[c-sharp]  view plain copy
  1. // 数据操作  
  2. 2 $("#msg").data("name""Hello, world.");  
  3. 3 alert($("#msg").data("name"));  
  4. 4 $("#msg").removeData("name");  
  5. 5 alert($("#msg").data("name"));  
 

 

回到目录

jQuery 原理的模拟代码 -3 事件处理

在 jQuery 中,实际注册的事件处理函数是一个匿名的闭包函数,这个函数最终都是通过调用 jQuery.event.handle 进行处理的。

 

在对象的私有扩展对象上,专门增加了一个名为 events 的事件管理对象,在这个对象上每种事件分别对应一个同名的属性,这个属性的值是一个数组,针对这个事件的处理程序依次压入这个数组中,构成一个事件处理的列表。自定义的事件处理函数即被压入这个列表中。

 

在事件触发的时候,通过注册的匿名函数来执行 jQuery.event.handle ,由于使用了闭包,所以在这个函数中的 this 就是事件源对象,通过这个事件源对象找到对象的私有扩展数据,然后在 events 中找到对应的事件处理程序列表,最后,依次执行。

 

[c-sharp]  view plain copy
  1.   1 /// <reference path="jQuery-core.js" />  
  2.   2 // #2076  
  3.   3   
  4.   4 // 用于生成事件处理函数的 id  
  5.   5 jQuery.guid = 1;  
  6.   6   
  7.   7 // jQuery 的事件对象  
  8.   8 jQuery.event = {    // # 1555  
  9.   9   
  10.  10     // 为对象增加事件  
  11.  11     // elem 增加事件的元素, type 事件的名称, handler 事件处理程序, data 事件相关的数据  
  12.  12     add: function (elem, type, handler, data) {  
  13.  13   
  14.  14         var handleObjIn, handleObj;  
  15.  15   
  16.  16         // 确认函数有一个唯一的 ID  
  17.  17         if (!handler.guid) {  
  18.  18             handler.guid = jQuery.guid++;  
  19.  19         }  
  20.  20   
  21.  21         // 取得这个元素所对应的缓存数据对象  
  22.  22         var elemData = jQuery.data(elem);  
  23.  23   
  24.  24         // 取得元素对应的缓存对象上的事件对象和所有事件共用的处理程序  
  25.  25         var events = elemData.events = elemData.events || {};  
  26.  26         var eventHandle = elemData.handle;  
  27.  27   
  28.  28         // 是否已经有事件处理函数 handle 只有一个,都是使用 jQuery.event.handle  
  29.  29         // 通过使用闭包,使得这个函数引用当前的事件对象,参数。  
  30.  30         if (!eventHandle) {  
  31.  31             elemData.handle = eventHandle = function () {  
  32.  32                 return jQuery.event.handle.apply(eventHandle.elem, arguments);  
  33.  33             };  
  34.  34         }  
  35.  35                   
  36.  36         // 使得闭包处理程序可以找到事件源对象  
  37.  37         eventHandle.elem = elem;  
  38.  38   
  39.  39         //   
  40.  40         handleObj = { handler: handler, data: data};  
  41.  41         handleObj.namespace = "";  
  42.  42   
  43.  43   
  44.  44         handleObj.type = type;  
  45.  45         handleObj.guid = handler.guid;  
  46.  46   
  47.  47         // 每种事件可以有一系列的处理程序,数组形式  
  48.  48         var handlers = events[type],  
  49.  49         special = jQuery.event.special[type] || {};  
  50.  50   
  51.  51         // Init the event handler queue  
  52.  52         if (!handlers) {  
  53.  53             handlers = events[type] = [];  
  54.  54   
  55.  55             // Check for a special event handler  
  56.  56             // Only use addEventListener/attachEvent if the special  
  57.  57             // events handler returns false  
  58.  58             // 完成实际的事件注册  
  59.  59             // 实际的事件处理函数是 eventHandle  
  60.  60             if (!special.setup || special.setup.call(elem, data, namespaces, eventHandle) === false) {  
  61.  61                 // Bind the global event handler to the element  
  62.  62                 if (elem.addEventListener) {  
  63.  63                     elem.addEventListener(type, eventHandle, false);  
  64.  64   
  65.  65                 } else if (elem.attachEvent) {  
  66.  66                     elem.attachEvent("on" + type, eventHandle);  
  67.  67                 }  
  68.  68             }  
  69.  69         }  
  70.  70   
  71.  71         // 自定义的处理函数在一个堆栈中,以后 jQuery.event.handle 到这里找到实际的处理程序  
  72.  72         handlers.push(handleObj);  
  73.  73                  
  74.  74         // Nullify elem to prevent memory leaks in IE  
  75.  75         elem = null;  
  76.  76     },  
  77.  77   
  78.  78     global: {},  
  79.  79   
  80.  80     // 真正的事件处理函数,   
  81.  81     // 由于是通过  return jQuery.event.handle.apply(eventHandle.elem, arguments) 调用的  
  82.  82     // 所以,此时的 this 就是事件源对象,event 是事件参数  
  83.  83     handle: function (event) {  // 1904  
  84.  84         var all, handlers, namespaces, namespace, events;  
  85.  85   
  86.  86         event = window.event;  
  87.  87         event.currentTarget = this;  
  88.  88   
  89.  89         // 在当前的事件对象上找到事件处理列表  
  90.  90         var events = jQuery.data(this"events"), handlers = events[event.type];  
  91.  91   
  92.  92         if (events && handlers) {  
  93.  93             // Clone the handlers to prevent manipulation  
  94.  94             handlers = handlers.slice(0);  
  95.  95   
  96.  96             for (var j = 0, l = handlers.length; j < l; j++) {  
  97.  97                 var handleObj = handlers[j];  
  98.  98   
  99.  99   
  100. 100                 // 取得注册事件时保存的参数  
  101. 101                 event.handler = handleObj.handler;  
  102. 102                 event.data = handleObj.data;  
  103. 103                 event.handleObj = handleObj;  
  104. 104   
  105. 105                 var ret = handleObj.handler.apply(this, arguments);  
  106. 106             }  
  107. 107         }  
  108. 108   
  109. 109         return event.result;  
  110. 110     },  
  111. 111   
  112. 112     // #2020  
  113. 113     special: {}  
  114. 114   
  115. 115 }  
  116. 116   
  117. 117 // bind 函数定义  
  118. 118 jQuery.fn.bind = function( type, fn)  
  119. 119 {  
  120. 120     var handler = fn;  
  121. 121   
  122. 122     // 调用 jQuery.event.add 添加事件  
  123. 123     for (var i = 0, l = this.length; i < l; i++) {  
  124. 124             jQuery.event.add(this[i], type, handler);  
  125. 125         }  
  126. 126     return this;  
  127. 127 }  
  128. 128   
  129. 129 jQuery.fn.unbind = function (type, fn) {  
  130. 130     // Handle object literals  
  131. 131     if (typeof type === "object" && !type.preventDefault) {  
  132. 132         for (var key in type) {  
  133. 133             this.unbind(key, type[key]);  
  134. 134         }  
  135. 135   
  136. 136     } else {  
  137. 137         for (var i = 0, l = this.length; i < l; i++) {  
  138. 138             jQuery.event.remove(this[i], type, fn);  
  139. 139         }  
  140. 140     }  
  141. 141   
  142. 142     return this;  
  143. 143 }  
  144. 144 // click 事件的注册方法  
  145. 145 jQuery.fn.click = function (fn) {  
  146. 146     this.bind("click", fn);  
  147. 147     return this;  
  148. 148 }  
 

 

这样,对于页面上的 id 为 msg 的元素,就可以通过下面的代码注册一个 click 事件处理函数。

[c-sharp]  view plain copy
  1. // 事件操作  
  2. 2 $("#msg").click(  
  3. 3     function () {  
  4. 4         alert(this.innerHTML);  
  5. 5     }  
  6. 6     );  
 

 

回到目录

jQuery 原理的模拟代码 -4 重要的扩展函数 extend

在上两篇文章中,我们看到每次要通过 jQuery 的原型增加共享方法的时候,都需要通过 jQuery.fn 一个个进行扩展,非常麻烦,jQuery.fn.extend 提供了一个扩展机制,可以方便我们通过一个或者多个示例对象来扩展某个对象。如果没有指定被扩展的对象,那么将扩展到自己身上。

 

jQuery.extend 也可以通过 jQuery.fn.extend 使用, 在 jQuery 中使用很多,用来为一个目标对象扩展成员,扩展的成员来自于一系列参考对象。

 

这样,如果我们需要为 jQuery.fn 扩展成员 removeData,就可以这样进行。

[c-sharp]  view plain copy
  1. jQuery.fn.extend(  
  2.   {  
  3.           removeData: function( key ) {  
  4.                return this.each(function() {  
  5.                    jQuery.removeData( this, key );  
  6.                });  
  7.           }  
  8.   }  
  9. );  
 

 

extend 的源码如下,因为比较简单,所以没有做太多的精简。

 

[c-sharp]  view plain copy
  1. /// <reference path="jQuery-core.js" />  
  2.  2   
  3.  3  
  4.  4 jQuery.extend = jQuery.fn.extend = function () {  
  5.  5     // copy reference to target object  
  6.  6     var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;  
  7.  7   
  8.  8     // 深拷贝情况,第一个参数为 boolean 类型,那么,表示深拷贝,第二个参数为目标对象  
  9.  9     if (typeof target === "boolean") {  
  10. 10         deep = target;  
  11. 11         target = arguments[1] || {};  
  12. 12         // skip the boolean and the target  
  13. 13         i = 2;  
  14. 14     }  
  15. 15   
  16. 16     // 如果目标不是对象也不是函数  
  17. 17     if (typeof target !== "object" && !jQuery.isFunction(target)) {  
  18. 18         target = {};  
  19. 19     }  
  20. 20   
  21. 21     // 如果只有一个参数就是扩展自己  
  22. 22     if (length === i) {  
  23. 23         target = this;  
  24. 24         --i;  
  25. 25     }  
  26. 26   
  27. 27     // 遍历所有的参考对象,扩展到目标对象上  
  28. 28     for (; i < length; i++) {  
  29. 29         // Only deal with non-null/undefined values  
  30. 30         if ((options = arguments[i]) != null) {  
  31. 31             // Extend the base object  
  32. 32             for (name in options) {  
  33. 33                 src = target[name];  
  34. 34                 copy = options[name];  
  35. 35   
  36. 36                 // Prevent never-ending loop  
  37. 37                 if (target === copy) {  
  38. 38                     continue;  
  39. 39                 }  
  40. 40   
  41. 41                 // Recurse if we're merging object literal values or arrays  
  42. 42                 if (deep && copy && (jQuery.isPlainObject(copy) || jQuery.isArray(copy))) {  
  43. 43                     var clone = src && (jQuery.isPlainObject(src) || jQuery.isArray(src)) ? src  
  44. 44                         : jQuery.isArray(copy) ? [] : {};  
  45. 45   
  46. 46                     // Never move original objects, clone them  
  47. 47                     target[name] = jQuery.extend(deep, clone, copy);  
  48. 48   
  49. 49                     // Don't bring in undefined values  
  50. 50                 } else if (copy !== undefined) {  
  51. 51                     target[name] = copy;  
  52. 52                 }  
  53. 53             }  
  54. 54         }  
  55. 55     }  
  56. 56   
  57. 57     // Return the modified object  
  58. 58     return target;  
  59. 59 };  
 

 

回到目录

jQuery 原理的模拟代码 -5 Ajax

 

对于 xhr 对象来说,我们主要通过异步方式访问服务器,在 onreadystatechange 事件中处理服务器回应的内容。简单的 xhr 使用如下所示。

 

[c-sharp]  view plain copy
  1.  1 // 创建 XHR 对象  
  2.  2 var xhr;  
  3.  3 if (window.XMLHttpRequest) {  
  4.  4     xhr = new XMLHttpRequest();  
  5.  5 }  
  6.  6 else if (window.ActiveXObject) {  
  7.  7     xhr = new ActiveXObject("Msxml2.XMLHTTP");  
  8.  8 }  
  9.  9 else {  
  10. 10     throw new Error("Ajax is not supported by this browser");  
  11. 11 }  
  12. 12   
  13. 13 function ready()  
  14. 14 {  
  15. 15     alert("Start......");  
  16. 16                   
  17. 17     // 通过事件来处理异步请求  
  18. 18     xhr.onreadystatechange = function()  
  19. 19     {  
  20. 20         if( xhr.readyState == 4 )  
  21. 21         {  
  22. 22             alert( "Ready.");  
  23. 23             if( xhr.status == 200 )  
  24. 24             {  
  25. 25                 alert("成功获得服务器返回的结果.");  
  26. 26                               
  27. 27                 // 请求结束之后,可以获取服务器返回的内容  
  28. 28                 alert( xhr.responseText );  
  29. 29                   
  30. 30                 // 获取服务器返回的 json 对象  
  31. 31                 var alice = eval( "(" + xhr.responseText + ")"   );  
  32. 32                 alert( alice.name );  
  33. 33             }  
  34. 34         }  
  35. 35     };  
  36. 36                   
  37. 37     // 设置请求参数  
  38. 38     xhr.open("get""data.json" );  
  39. 39     xhr.send( null );  
  40. 40 }  
 

 

jQuery 简单地包装了对 xhr 对象的使用,通过对 jQuery 对象增加常用的访问方法,然后,提供给 jQuery 对象来使用。

 

[c-sharp]  view plain copy
  1.  1 // 主要的扩展在 jQuery.ajax 中。  
  2.  2 jQuery.extend({     // #6299  
  3.  3     // 请求的默认参数  
  4.  4     ajaxSettings: {  
  5.  5         url: location.href,  
  6.  6         type: "GET",  
  7.  7         contentType: "application/x-www-form-urlencoded",  
  8.  8         data: null,  
  9.  9         xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?  
  10. 10             function () {  
  11. 11                 return new window.XMLHttpRequest();  
  12. 12             } :  
  13. 13             function () {  
  14. 14                 try {  
  15. 15                     return new window.ActiveXObject("Microsoft.XMLHTTP");  
  16. 16                 } catch (e) { }  
  17. 17             }  
  18. 18         },  
  19. 19   
  20. 20     // 用来设置 jQuery.ajaxSettings ,设置请求的参数  
  21. 21     ajaxSetup: function (settings) {  
  22. 22         jQuery.extend(jQuery.ajaxSettings, settings);  
  23. 23     },  
  24. 24   
  25. 25     ajax: function (origSettings) {      // 实际的 ajax 函数  
  26. 26         var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);  
  27. 27   
  28. 28         // 创建 xhr 对象  
  29. 29         xhr = s.xhr();  
  30. 30         // 回调函数  
  31. 31         var onreadystatechange = xhr.onreadystatechange = function (isTimeout) {  
  32. 32             if (xhr.readyState === 4) {  
  33. 33                 if (xhr.status == 200) {  
  34. 34                     s.success.call(origSettings, xhr.responseText);  
  35. 35                 }  
  36. 36             }  
  37. 37         };  
  38. 38           
  39. 39         // 设置请求参数  
  40. 40         xhr.open(s.type, s.url);  
  41. 41   
  42. 42         // Send the data    发出请求  
  43. 43         xhr.send(s.data);  
  44. 44   
  45. 45         // return XMLHttpRequest to allow aborting the request etc.  
  46. 46         return xhr;  
  47. 47     },  
  48. 48   
  49. 49     // 使用 get 方式发出 ajax 请求的方法  
  50. 50     get: function (url, data, callback, type) {  
  51. 51         // shift arguments if data argument was omited  
  52. 52         if (jQuery.isFunction(data)) {  
  53. 53             type = type || callback;  
  54. 54             callback = data;  
  55. 55             data = null;  
  56. 56         }  
  57. 57   
  58. 58         return jQuery.ajax({  
  59. 59             type: "GET",  
  60. 60             url: url,  
  61. 61             data: data,  
  62. 62             success: callback,  
  63. 63             dataType: type  
  64. 64         });  
  65. 65     }  
  66. 66   
  67. 67   
  68. 68 });       // #6922  
  69. 69   
  70. 70 // 扩展 jQuery 对象,增加 load 方法  
  71. 71 jQuery.fn.extend(  
  72. 72     {  
  73. 73         load: function (url) {  
  74. 74             var self = this;  
  75. 75             jQuery.get(url, function (data) {  
  76. 76                 self.each(function () {  
  77. 77                     this.innerHTML = data;  
  78. 78                 }         
  79. 79             )    
  80. 80             }     
  81. 81         )  
  82. 82         }  
  83. 83     }  
  84. 84 )  
 

 

在页面中,可以如下使用。

 

[c-sharp]  view plain copy
  1.  1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2.  2 <html xmlns="http://www.w3.org/1999/xhtml">  
  3.  3 <head>  
  4.  4     <title></title>  
  5.  5 </head>  
  6.  6 <body>  
  7.  7     <input type="button" id="btn" value="Click me" />  
  8.  8     <div id="msg">  
  9.  9     </div>  
  10. 10     <mce:script src="jQuery-core.js" mce_src="jQuery-core.js" type="text/javascript"></mce:script>  
  11. 11     <mce:script src="jQuery-event-2.js" mce_src="jQuery-event-2.js" type="text/javascript"></mce:script>  
  12. 12     <mce:script src="jQuery-data.js" mce_src="jQuery-data.js" type="text/javascript"></mce:script>  
  13. 13     <mce:script src="jQuery-extend.js" mce_src="jQuery-extend.js" type="text/javascript"></mce:script>  
  14. 14     <mce:script src="jQuery-ajax.js" mce_src="jQuery-ajax.js" type="text/javascript"></mce:script>  
  15. 15     <mce:script type="text/javascript"><!--  
  16. 16   
  17. 17             $("#btn").click(function () {  
  18. 18                 $("#msg").load("hello.txt");  
  19. 19             })  
  20. 20           
  21. 21   
  22. 22       
  23. // --></mce:script>  
  24. 23 </body>  
  25. 24 </html>  
  26. 25   
  

 

回到目录



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值