jQuery核心詳解與實踐讀書筆記1:原型技術分解2
7. 延續--功能擴充 jQuery架構是通過extend()函數來擴充功能的,extend()函數的功能實現起來也很簡單,它只是吧指定對象的方法複製給jQuery對象或jQuery.prototype對象,如下範例程式碼就為jQuery類和原型定義了一個擴充功能的函數extend()。 複製代碼 1 var $ = jQuery = function(selector, context) { //定義類 2 return new jQuery.fn.init(selector, context); //返回選取器的執行個體 3 }; 4 jQuery.fn = jQuery.prototype = { //jQuery類的原型對象 5 init : function(selector, context) { //定義選取器構造器 6 selector = selector || document; //設定預設值為document 7 context = context || document; //設定預設值為document 8 if(selector.nodeType) { //如果選擇符為節點對象 9 this[0] = selector; //把參數節點傳遞給執行個體對象的數組10 this.length = 1; //並設定執行個體對象的length屬性,定義包含的元素個數11 this.context = selector; //設定執行個體的屬性,返回選擇範圍12 return this; //返回當前執行個體13 }14 if(typeof selector === "string") { //如果選擇符是字串15 var e = context.getElementsByTagName(selector); //擷取指定名稱的元素16 for(var i=0; i<e.length; i++) { //遍曆元素集合,並把所有元素填入到當前執行個體數組中17 this[i] = e[i];18 }19 this.length = e.length; //設定執行個體的length屬性,即定義包含的元素個數20 this.context = context; //設定執行個體的屬性,返回選擇範圍21 return this; //返回當前執行個體22 } else {23 this.length = 0; //否則,設定執行個體的length屬性值為024 this.context = context; //設定執行個體的屬性,返回選擇範圍25 return this; //返回當前執行個體26 }27 },28 jquery : "1.3.2", //原型屬性29 size : function() { //原型方法30 return this.length;31 }32 };33 jQuery.fn.init.prototype = jQuery.fn; //使用jQuery的原型對象覆蓋init的原型對象34 //jQuery功能擴充函數35 jQuery.extend = jQuery.fn.extend = function(obj) {36 for(var prop in obj) {37 this[prop] = obj[prop];38 }39 return this;40 };41 //擴充jQuery對象方法42 jQuery.fn.extend({43 test : function() {44 alert("測試擴充功能");45 }46 });複製代碼在上面的代碼中,先定義了一個功能擴充函數extend(),然後為jQuery.fn原型對象調用extend()函數,為其添加一個測試方法test()。這樣就可以在實踐中應用,如$("div").test()。 jQuery架構定義的extend()函數的功能要強大很多,它不僅能夠完成基本的功能擴充,還可以實現對象合并等功能,代碼和解釋如下所示: 複製代碼 1 var $ = jQuery = function(selector, context) { //定義類 2 return new jQuery.fn.init(selector, context); //返回選取器的執行個體 3 }; 4 jQuery.fn = jQuery.prototype = { //jQuery類的原型對象 5 init : function(selector, context) { //定義選取器構造器 6 selector = selector || document; //設定預設值為document 7 context = context || document; //設定預設值為document 8 if(selector.nodeType) { //如果選擇符為節點對象 9 this[0] = selector; //把參數節點傳遞給執行個體對象的數組10 this.length = 1; //並設定執行個體對象的length屬性,定義包含的元素個數11 this.context = selector; //設定執行個體的屬性,返回選擇範圍12 return this; //返回當前執行個體13 }14 if(typeof selector === "string") { //如果選擇符是字串15 var e = context.getElementsByTagName(selector); //擷取指定名稱的元素16 for(var i=0; i<e.length; i++) { //遍曆元素集合,並把所有元素填入到當前執行個體數組中17 this[i] = e[i];18 }19 this.length = e.length; //設定執行個體的length屬性,即定義包含的元素個數20 this.context = context; //設定執行個體的屬性,返回選擇範圍21 return this; //返回當前執行個體22 } else {23 this.length = 0; //否則,設定執行個體的length屬性值為024 this.context = context; //設定執行個體的屬性,返回選擇範圍25 return this; //返回當前執行個體26 }27 },28 jquery : "1.3.2", //原型屬性29 size : function() { //原型方法30 return this.length;31 }32 };33 jQuery.fn.init.prototype = jQuery.fn; //使用jQuery的原型對象覆蓋init的原型對象34 //jQuery功能擴充函數35 jQuery.extend = jQuery.fn.extend = function(obj) {36 //定義複製操作的目標對象37 var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;38 //擷取是否深度複製處理39 if( typeof target === "boolean") {40 deep = target;41 target = arguments[i] || {};42 //跳出布爾值和目標對象43 i = 2;44 }45 //如果第一個參數是字串,則設定為空白對象46 if(typeof target !== "object" && !jQuery.isFunction(target)) {47 target = {};48 }49 //如果只有一個參數,表示把參數對象的方法複製給當前對象,則設定target為this50 if(length == i) {51 target = this;52 --i;53 }54 for( ; i<length; i++) {55 //若參數值不為null,則進行處理56 if((options = arguments[i]) != null) {57 //擴充基類對象58 for( var name in options) { //遍曆參數對象59 var src = target[name], copy = options[name];60 //防止死迴圈61 if(target === copy) {62 continue;63 }64 //遞迴運算65 if(deep && copy && typeof copy === "object" && !copy.nodeType) {66 target[name] = jQuery.extend(deep, 67 //不要複製原對象68 src || (copy.length != null ? [] : {}), copy);69 } else if(copy != undefined) { //不要傳遞未定義的值70 target[name] = copy;71 }72 }73 }74 }75 //返回修改後的對象76 return target;77 };複製代碼以上代碼就是jQuery架構提供的功能擴充代碼。 8. 延續--參數處理 jQuery的方法都要求傳遞的參數為對象結構,這是因為jQuery架構的很多方法都包含大量的參數,且都是可選的,位置也沒有固定的要求,所以使用對象直接量是唯一的解決方案。使用對象直接量作為參數傳遞的載體,如何解析並提出參數?如何處理參數的預設值?可以通過下面的方式: 複製代碼 1 var $ = jQuery = function(selector, context) { //定義類 2 return new jQuery.fn.init(selector, context); //返回選取器的執行個體 3 }; 4 jQuery.fn = jQuery.prototype = { //jQuery類的原型對象 5 init : function(selector, context) { //定義選取器構造器 6 selector = selector || document; //設定預設值為document 7 context = context || document; //設定預設值為document 8 if(selector.nodeType) { //如果選擇符為節點對象 9 this[0] = selector; //把參數節點傳遞給執行個體對象的數組10 this.length = 1; //並設定執行個體對象的length屬性,定義包含的元素個數11 this.context = selector; //設定執行個體的屬性,返回選擇範圍12 return this; //返回當前執行個體13 }14 if(typeof selector === "string") { //如果選擇符是字串15 var e = context.getElementsByTagName(selector); //擷取指定名稱的元素16 for(var i=0; i<e.length; i++) { //遍曆元素集合,並把所有元素填入到當前執行個體數組中17 this[i] = e[i];18 }19 this.length = e.length; //設定執行個體的length屬性,即定義包含的元素個數20 this.context = context; //設定執行個體的屬性,返回選擇範圍21 return this; //返回當前執行個體22 } else {23 this.length = 0; //否則,設定執行個體的length屬性值為024 this.context = context; //設定執行個體的屬性,返回選擇範圍25 return this; //返回當前執行個體26 }27 },28 setOptions : function(options) {29 this.options = { //方法的預設值,可以擴充30 StartColor : "#000",31 EndColor : "#DDC",32 Background : false,33 Step : 20,34 Speed : 1035 };36 jQuery.extend(this.options, options || {}); //如果傳遞參數,則覆蓋原預設參數37 }38 };39 jQuery.fn.init.prototype = jQuery.fn; //使用jQuery的原型對象覆蓋init的原型對象40 //jQuery功能擴充函數41 jQuery.extend = jQuery.fn.extend = function(destination, source) {//重新定義extend()函數42 for(var property in source) {43 destination[property] = source[proprty];44 }45 return destination;46 };複製代碼在上面的樣本中,定義了一個原型方法setOptions(),該方法能夠對傳遞的參數對象進行處理,並覆蓋預設值。在jQuery架構中,extend()函數包含了所有功能,它既能為當前對象擴充方法,也能處理參數對象,並覆蓋預設值。 9. 涅槃--名字空間 在介紹該內容前,先介紹一個JavaScript函數中的一個核心概念:閉包,其實就是匿名函數。閉包的一個很重要的作用就是將閉包內部的代碼封裝在一個封閉的空間中,不將內部的資訊暴露出來,別的代碼也不能隨意訪問閉包內的函數或變數等。只需要提供外接可以訪問的介面,就可以方便的與外接進行聯絡。 我們看jQuery原始碼時就會發現,它幾千行的代碼就是封裝在一個閉包之中的,這樣就解決了架構內部的變數名與其它架構或JavaScript代碼重名衝突問題。另外jQuery架構的$和jQuery名字也很有可能發生名字衝突,這個問題jQuery架構是如何解決的呢? 首先,jQuery的所有代碼全部封裝在一個閉包(即匿名函數)中其次,jQuery提供了一個noConfilit()函數,該函數實現禁止jQuery架構使用這兩個名字。 那它又是如何做的呢? jQuery在架構的最前面,先使用_$和_jQuery臨時變數寄存$和jQuery這兩個變數的內容,當需要禁用jQuery架構的名字時,可以使用一個臨時變數_$和_jQuery恢複$和jQuery這兩個變數的實際內容。代碼如下: 複製代碼 1 (function(){ 2 var window = this, 3 undefined, 4 _jQuery = window.jQuery, //緩衝jQuery變數內容 5 _$ = window.$, 6 jQuery = window.jQuery = window.$ = function(selector, context) { 7 return new jQuery.fn.init(selector, context); 8 }, 9 quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,10 isSimple = /^.[^:#\[\.,]*$/;11 jQuery.fn = jQuery.prototype = {12 init : function(selector, context) {}13 };14 })(); 複製代碼至此,jQuery架構的簡單雛形就已經搭好了,雖然jQuery架構的功能是極其強大的,但是它也是在這個架構上建立起來的。後面的工作就是根據應用需要或者功能需要,使用extend()函數不斷擴充jQuery架構的工具函數和jQuery對象的方法。