-
立即調(diào)用表達(dá)式 任何庫與框架設(shè)計(jì)的第一個(gè)要點(diǎn)就是解決命名空間與變量污染的問題。jQuery就是利用了JavaScript函數(shù)作用域的特性,采用立即調(diào)用表達(dá)式包裹了自身的方法來解決這個(gè)問題。 jQuery的立即調(diào)用函數(shù)表達(dá)式的寫法有三種: 寫法1: (function(window, factory) { factory(window) }(this, function() { return function() { //jQuery的調(diào)用 } })) 可以看出上面的代碼中嵌套了2個(gè)函數(shù),而且把一個(gè)函數(shù)作為參數(shù)傳遞到另一個(gè)函數(shù)中并且執(zhí)行,這種方法有點(diǎn)復(fù)雜,我們簡化一下寫法: 寫法2: var factory = function(){ return function(){ //執(zhí)行方法 } } var jQuery = factory(); 上面的代碼效果和方法1是等同的,但是這個(gè)factory有點(diǎn)變成了簡單的工廠方法模式,需要自己調(diào)用,不像是一個(gè)單例的jQuery類,所以我們需要改成“自執(zhí)行”,而不是另外調(diào)用。 寫法3: (function(window, undefined) { var jQuery = function() {} // ... window.jQuery = window.$ = jQuery; })(window);查看全部
-
靜態(tài)與實(shí)例方法共享設(shè)計(jì) jQuery在接口的設(shè)計(jì): 遍歷方法: $(".aaron").each() //作為實(shí)例方法存在 $.each() //作為靜態(tài)方法存在 這是最常見的遍歷方法,第一條語句是給有指定的上下文調(diào)用的,就是(".aaron")獲取的DOM合集,第二條語句$.each()函數(shù)可用于迭代任何集合,無論是“名/值”對象(JavaScript對象)或數(shù)組。在迭代數(shù)組的情況下,回調(diào)函數(shù)每次都會(huì)傳遞一個(gè)數(shù)組索引和相應(yīng)的數(shù)組值作為參數(shù)。本質(zhì)上來說2個(gè)都是遍歷,那么我們是不是要寫2個(gè)方法呢? 我們來看看jQuery的源碼: jQuery.prototype = { each: function( callback, args ) { return jQuery.each( this, callback, args ); } } 實(shí)例方法取于靜態(tài)方法,換句話來說這是靜態(tài)與實(shí)例方法共享設(shè)計(jì),靜態(tài)方法掛在jQuery構(gòu)造器上,原型方法掛在哪里呢? 我們上節(jié)不是講了內(nèi)部會(huì)劃分一個(gè)新的構(gòu)造器init嗎?jQuery通過new原型prototype上的init方法當(dāng)作構(gòu)造器,那么init的原型鏈方法就是實(shí)例的方法了,所以jQuery通過2個(gè)構(gòu)造器劃分2種不同的調(diào)用方式一種是靜態(tài),一種是原型。 方法是共享的,并且實(shí)例方法取于靜態(tài)方法,2個(gè)構(gòu)造器是完全隔離的 ,這個(gè)要如何處理? 看看jQuery給的方案: 畫龍點(diǎn)睛的一處init.prototype = jQuery.fn,把jQuery.prototype原型的引用賦給jQuery.fn.init.prototype的原型,這樣就把2個(gè)構(gòu)造器的原型給關(guān)聯(lián)起來了。 ajQuery.fn = ajQuery.prototype = { name: 'aaron', init: function(selector) { this.selector = selector; return this; }, constructor: ajQuery } ajQuery.fn.init.prototype = ajQuery.fn查看全部
-
var $$ = ajQuery = function(selector) { this.selector = selector; return new ajQuery(selector); } 是一個(gè)死循環(huán),為了避免死循環(huán) var $$ = ajQuery = function(selector) { //把原型上的init作為構(gòu)造器 return new ajQuery.fn.init( selector ); } init是ajQuery原型上作為構(gòu)造器的一個(gè)方法,所以通過new ajQuery.fn.init( selector );之后,那么init的this就不再是aJQuery了,init的this就完全引用不到aJQuery的原型了,所以這里通過new把init方法與aJQuery給分離成2個(gè)獨(dú)立的構(gòu)造器了.查看全部
-
jQuery為了避免出現(xiàn)這種死循環(huán)的問題,采取的手段是把原型上的一個(gè)init方法作為構(gòu)造器 var $$ = ajQuery = function(selector) { //把原型上的init作為構(gòu)造器 return new ajQuery.fn.init( selector ); } ajQuery.fn = ajQuery.prototype = { name: 'aaron', init: function() { console.log(this) }, constructor: ajQuery } 這樣確實(shí)解決了循環(huán)遞歸的問題,但是又問題來了,init是ajQuery原型上作為構(gòu)造器的一個(gè)方法,那么其this就不是ajQuery了,所以this就完全引用不到ajQuery的原型了,所以這里通過new把init方法與ajQuery給分離成2個(gè)獨(dú)立的構(gòu)造器。查看全部
-
分離構(gòu)造器 通過new操作符構(gòu)建一個(gè)對象,一般經(jīng)過四步: A.創(chuàng)建一個(gè)新對象 B.將構(gòu)造函數(shù)的作用域賦給新對象(所以this就指向了這個(gè)新對象) C.執(zhí)行構(gòu)造函數(shù)中的代碼 D.返回這個(gè)新對象 最后一點(diǎn)就說明了,我們只要返回一個(gè)新對象即可。其實(shí)new操作符主要是把原型鏈跟實(shí)例的this關(guān)聯(lián)起來,這才是最關(guān)鍵的一點(diǎn),所以我們?nèi)绻枰玩溇捅仨氁猲ew操作符來進(jìn)行處理。否則this則變成window對象了。 我們來剖析下jQuery的這個(gè)結(jié)構(gòu),以下是我們常見的類式寫法: var $$ = ajQuery = function(selector) { this.selector = selector; return this } ajQuery.fn = ajQuery.prototype = { selectorName:function(){ return this.selector; }, constructor: ajQuery } var a = new $$('aaa'); //實(shí)例化 a.selectorName() //aaa //得到選擇器名字 首先改造jQuery無new的格式,我們可以通過instanceof判斷this是否為當(dāng)前實(shí)例: var $$ = ajQuery = function(selector) { if(!(this instanceof ajQuery)){ return new ajQuery(selector); } this.selector = selector; return this } 但是注意千萬不要像下面這樣寫: var $$ = ajQuery = function(selector) { this.selector = selector; return new ajQuery(selector); } Uncaught RangeError: Maximum call stack size exceeded 這樣會(huì)無限遞歸自己,從而造成死循環(huán)并且溢出。查看全部
-
jQuery對象的構(gòu)建如果在性能上考慮,所以就必須采用原型式的結(jié)構(gòu): jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ); } jQuery.fn = jQuery.prototype = { init:function(){ return this }, jquery: version, constructor: jQuery, ……………… } var a = $() ; 使用原型結(jié)構(gòu),性能上是得到了優(yōu)化,但是ajQuery類這個(gè)結(jié)構(gòu)與目標(biāo)jQuery的結(jié)構(gòu)的還是有很大不一致: ? 沒有采用new操作符; ? return返回的是一個(gè)通過new出來的的對象 。查看全部
-
函數(shù)在充當(dāng)類的構(gòu)造器時(shí),原型prototype是一個(gè)重要的概念。prototype是構(gòu)造函數(shù)的一個(gè)屬性, 該屬性指向一個(gè)對象。而這個(gè)對象將作為該構(gòu)造函數(shù)所創(chuàng)建的所有實(shí)例的基引用(base reference), 可以把對象的基引用想像成一個(gè)自動(dòng)創(chuàng)建的隱藏屬性。 當(dāng)訪問對象的一個(gè)屬性時(shí), 首先查找對象本身, 找到則返回;若不, 則查找基引用指向的對象的屬性(如果還找不到實(shí)際上還會(huì)沿著原型鏈向上查找, 直至到根)。 只要沒有被覆蓋的話, 對象原型的屬性就能在所有的實(shí)例中找到。 類一: function ajQuery() { this.name = 'jQuery'; this.sayName = function(){ return this.name } var a = new ajQuery() var b = new ajQuery() var c = new ajQuery() 類二: function ajQuery() { this.name = 'jQuery' } ajQuery.prototype = { sayName: function() { return this.name } } var a = new ajQuery() var b = new ajQuery() var c = new ajQuery() 類一與類二產(chǎn)生的結(jié)構(gòu)幾乎是一樣的,而本質(zhì)區(qū)別就是:類二new產(chǎn)生的a、b、c三個(gè)實(shí)例對象共享了原型的sayName方法,這樣的好處節(jié)省了內(nèi)存空間,類一則是要為每一個(gè)實(shí)例復(fù)制sayName方法,每個(gè)方法屬性都占用一定的內(nèi)存的空間,所以如果把所有屬性方法都聲明在構(gòu)造函數(shù)中,就會(huì)無形的增大很多開銷,這些實(shí)例化的對象的屬性一模一樣,都是對this的引用來處理。除此之外類一的所有方法都是拷貝到當(dāng)前實(shí)例對象上。類二則是要通過scope連接到原型鏈上查找,這樣就無形之中要多一層作用域鏈的查找了。查看全部
-
如果我們需要同時(shí)使用jQuery和其他JavaScript庫,我們可以使用 $.noConflict()把$的控制權(quán)交給其他庫。舊引用的$ 被保存在jQuery的初始化; noConflict() 簡單的恢復(fù)它們。 通過類似swap交換的概念,先把之前的存在的命名空間給緩存起來,通過對比當(dāng)前的命名空間達(dá)到交換的目的,首先,我們先判斷下當(dāng)前的的$空間是不是被jQuery接管了,如果是則讓出控制權(quán)給之前的_$引用的庫,如果傳入deep為true的話等于是把jQuery的控制權(quán)也讓出去了。 如果不通過noConflict處理的話其后果可想而知,香噴噴的$大家都“覬覦已久”。查看全部
-
jQuery多庫共存處理 多庫共存換句話說可以叫無沖突處理。 總的來說會(huì)有2種情況會(huì)遇到: 1、$太火熱,jQuery采用$作為命名空間,不免會(huì)與別的庫框架或者插件相沖突。 2、jQuery版本更新太快,插件跟不上,導(dǎo)致不同版本對插件的支持度不一樣。 出于以上的原因,jQuery給出了解決方案–– noConflict函數(shù)。 引入jQuery運(yùn)行這個(gè)noConflict函數(shù)將變量$的控制權(quán)讓給第一個(gè)實(shí)現(xiàn)它的那個(gè)庫,確保jQuery不會(huì)與其他庫的$對象發(fā)生沖突。 在運(yùn)行這個(gè)函數(shù)后,就只能使用jQuery變量訪問jQuery對象。例如,在要用到$("aaron")的地方,就必須換成jQuery("aaron"),因?yàn)?的控制權(quán)已經(jīng)讓出去了。 使用DEMO: jQuery.noConflict(); // 使用 jQuery jQuery("aaron").show(); // 使用其他庫的 $() $("aaron").style.display = ‘block’; 這個(gè)函數(shù)必須在你導(dǎo)入jQuery文件之后,并且在導(dǎo)入另一個(gè)導(dǎo)致沖突的庫之前使用。當(dāng)然也應(yīng)當(dāng)在其他沖突的庫被使用之前,除非jQuery是最后一個(gè)導(dǎo)入的。 由于比較簡單,我們直接上代碼解說: Var _jQuery = window.jQuery, _$ = window.$; jQuery.noConflict = function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; };查看全部
-
一個(gè)是ready一個(gè)是load,這兩個(gè)到底有什么區(qū)別呢? ready與load誰先執(zhí)行: 大家在面試的過程中,經(jīng)常會(huì)被問到一個(gè)問題:ready與load那一個(gè)先執(zhí)行,那一個(gè)后執(zhí)行?答案是ready先執(zhí)行,load后執(zhí)行。 DOM文檔加載的步驟: 要想理解為什么ready先執(zhí)行,load后執(zhí)行就要先了解下DOM文檔加載的步驟: (1) 解析HTML結(jié)構(gòu)。 (2) 加載外部腳本和樣式表文件。 (3) 解析并執(zhí)行腳本代碼。 (4) 構(gòu)造HTML DOM模型。//ready (5) 加載圖片等外部文件。 (6) 頁面加載完畢。//load 從上面的描述中大家應(yīng)該已經(jīng)理解了吧,ready在第(4)步完成之后就執(zhí)行了,但是load要在第(6)步完成之后才執(zhí)行。查看全部
-
回溯處理: .preObject() .end() .addBack()查看全部
-
jQuery插件的兩種開發(fā)方式: (1)掛的jQuery命名空間下人全局函數(shù),也可稱為靜態(tài)方法; (2)jQuery對象級別人方法,即掛的jQuery原型下的方法,這樣通過選擇器獲取人jQuery對象實(shí)例也可以共享該方法。 接口:$.extend(target, [object1], [objectN]); 接口使用: jQuery.extend({ data: function() {}, removeData: function() {} }); jQuery.fn.extend({ data: function() {}, removeData: function() {} }); jQuery.extend調(diào)用的時(shí)候上下文指的是jQuery構(gòu)造器,而jQuery.fn.extend調(diào)用人時(shí)候上下文指向的是jQuery構(gòu)造器人實(shí)例對象了。查看全部
-
實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用的原理是在方法內(nèi)部返回當(dāng)前這個(gè)實(shí)例對象this。 優(yōu)點(diǎn):能夠節(jié)省代碼量,提高代碼人效率,代碼看起來更簡潔。 缺點(diǎn):所有對象的方法都返回this,就高不能餓自己的返回值,不一定適合所有場合。查看全部
-
通過原型傳遞,實(shí)現(xiàn)實(shí)例方法和靜態(tài)方法共享設(shè)計(jì)。查看全部
-
使用$.noConflict();讓出$的控制權(quán),可以通過閉包隔離,將$轉(zhuǎn)為局部變量使用。查看全部
舉報(bào)
0/150
提交
取消