免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
jQuery誕生記

by zhangxinxu from http://www.zhangxinxu.com

本文地址:http://www.zhangxinxu.com/wordpress/?p=3520


一、看似偶然的東西實際是必然會發(fā)生的


我大學時候在圖書館翻過一本很破舊的書,講生物理論的,主要內(nèi)容就是探討生命的產(chǎn)生是偶然還是必然。里面很多亞里士多德都看不懂的公式計算什么的,還有模擬原始地球環(huán)境出現(xiàn)了有機物的實驗什么的

。總之,書論述的觀點是:“在當時的地球環(huán)境下,生命的產(chǎn)生是必然的!” 無數(shù)次機會的偶然條件、無數(shù)次化合物的相遇反應等必定會產(chǎn)生有機物,再有N多偶然,有機物必然形成了有機體……


這種理論類似于,你是個過馬路非常小心的人,且你萬壽無疆,除了怕被汽車撞。給你100萬年的壽命,你最后必然還是被車撞死。


如果以這種理論來看jQuery的出現(xiàn),結論也應該是必然的!


二、需求、動力、發(fā)展、事物產(chǎn)生與jQuery的誕生



一個成熟的東西顯然不是一口氣就出來的,所謂“一鏟子挖不了一口井”,我想jQuery的原作者再天才,也是循序漸進過來的,如何個循序漸進法,我想,很有可能就是需求驅動而產(chǎn)生的,好比上圖刀削面機器人,據(jù)說現(xiàn)在已經(jīng)第八代了!


1. gelElementById太長了

頁面上有個按鈕,還有個圖片,我想點擊按鈕圖片隱藏,如下HTML:



<button id="button">點擊我</button><img id="image" src="xxx.jpg">


于是,我的腳本可能就這樣:



var button = document.getElementById("button")    , image = document.getElementById("image")button.onclick = function() {    image.style.display = "none";};


有何問題?人幾乎都是天生的“懶惰者”,document.getElementById名稱長且重復出現(xiàn),好像到了公司發(fā)現(xiàn)卡沒帶又回家重新拿卡的感覺,我希望越簡單越好。恩,

我很喜歡錢,$這個符號我很喜歡,我打算改造一番,簡化我的工作:



var $ = function(id) {    return document.getElementById(id);};$("button").onclick = function() {    $("image").style.display = "none";};


這里的$()就是最簡單的包裝器,只是返回的是原生的DOM對象。


2. 我需要一個簡潔的暗號,就像“芝麻開門”

后來頁面復雜了,點擊一個按鈕,有2張圖片要隱藏。



$("button").onclick = function() {    $("image1").style.display = "none";    $("image2").style.display = "none";};


好像又看見長長的重復的東西,xxx.style.display = "none", 為什么每次開門都要從包里找到鑰匙、對準插口插進去、還要左扭扭右扭扭呢?一次還好,天天經(jīng)常老是這樣怎受得了。設想,要是有個芝麻開門的暗號就好了,“open開”,聲音識別,門自動開了,多省心。


這里每次隱藏都要xxx.style.display = "none", 比每天拿鑰匙開門還要煩,我希望有一個快捷的方式,例如,“hide隱”,語句識別,元素自動隱藏,多省心。


就是要變成下面的效果:



$("button").onclick = function() {    $("image1").hide();    $("image2").hide();};


3. 如何識別“芝麻開門”的暗號

$("image1")本質是個DOM元素,$("image1").hide()也就是在DOM元素上擴展一個hide方法,調(diào)用即隱藏。


哦,擴展,立馬想到了JS中的prototype原型。//zxx: 老板,現(xiàn)在滿大街什么菜最便宜。老板:原型啊,都泛濫了!



HTMLElement.prototype.hide = function() {    this.style.display = "none";};


上面代碼的demo地址應該不會被人看到吧……


雖然在身體上鉆了個窟窿插進入了一個方法,畢竟瀏覽器有有效果啊,切膚之痛就不算什么了。但是,我們是在泱泱天朝,很多IE6~IE8老頑固,這些老東西不認識HTMLElement,對于HTMLElement自殘擴展之法根本理解不了,而這些老家伙掌管了半壁江山。唉,面對現(xiàn)實,元素直接擴展是行不通了。


因此,由于兼容性,我們需要想其他擴展方法。


4. 條條大路通羅馬,此處不留爺,自有留爺處

雖IE6~IE8不識HTMLElement原型擴展,但是,Function的原型擴展其認識啊。管不管用,暫時不得而知,先隨便搞個簡單的試試唄~



var F = function() {};F.prototype.hide = function() {    this?.style.display = "none";};new F().hide();    // 這個實現(xiàn)隱藏?


本文至少還有一半的內(nèi)容,但是,全文的最難點就在這里的,對new F()的認識和理解。


上面的代碼,new F()您可以看做是this?.style這里的this. 您可能會跳起來搶答道:“那new F()return值 = DOM元素不就完事OK啦!—— this.style.hide = new F().style.hide = DOM.style.hide”!



只要new表達式之后的constructor返回(return)一個引用對象(數(shù)組,對象,函數(shù)等),都將覆蓋new創(chuàng)建的匿名對象,如果返回(return)一個原始類型(無return時其實為return原始類型undefined),那么就返回new創(chuàng)建的匿名對象。



上面的引用來自這里。什么意思呢?說白了就是,new F()如果沒有返回值(Undefined類型),或返回值是5種基本型(Undefined類型、Null類型、Boolean類型、Number類型、String類型)之一,則new F()我們可以看成是原型擴展方法中的this; 如果返回是是數(shù)組啊、對象啊什么的,則返回值就是這些對象本身,此時new F()this


舉例說明:



var F = function(id) {    return document.getElementById(id);};new F("image1") == document.getElementById("image1");    // true 說明看上去返回DOM對象,實際確實就是DOM對象



var F = function(id) {    return id;};new F("image1") == "image1";    // false 說明看上去返回字符串值,實際并不是字符串


回到上面天真的想法。要想使用prototype.hide方法中的this, 偶們就不能讓F函數(shù)有亂七八糟的返回值。


因此,new F()直接返回DOM是不可取的,但我們可以借助this間接調(diào)用。比方說:



var F = function(id) {    this.element = document.getElementById(id);};F.prototype.hide = function() {    this.element.style.display = "none";};new F("image").hide();    // 看你還不隱藏


上面代碼的demo地址應該不會被人看到吧……


5. 我不喜歡太暴露

F()中的this.element實際上將element這個屬性直接暴露在了new F("image")上!



new F("image").hasOwnProperty("element");    // true



太暴露了,我不喜歡~~


如何隱藏?代碼如下:



var F = function(id) {    return this.getElementById(id);};F.prototype.getElementById = function(id) {    this.element = document.getElementById(id);    return this;};F.prototype.hide = function() {    this.element.style.display = "none";};new F("image").hide();    // 看你還不隱藏


元素獲取方法放在prototype上,通過F()執(zhí)行。你可能會奇怪了,你剛明明說“new F()直接返回DOM是不可取的”,怎么現(xiàn)在又有return呢?大家務必擦亮眼睛,F.prototype.getElementById的返回值是this,也就是new F()的返回值是this. 形象點就是new F("image")出了一拳,又反彈到自己臉上了。


于是乎,現(xiàn)在就沒有直接暴露的API了。


上面代碼的demo地址應該不會被人看到吧……


6. 我不喜歡new, 我喜歡$

new F("image")這種寫法我好不喜歡,我喜歡$, 我就是喜歡$, 我要換掉。


好吧,把new什么什么藏在$方法中把~



var $ = function(id) {    return new F(id);};


于是,上面的圖片隱藏的直接執(zhí)行代碼就是:



$("image").hide();


上面代碼的demo地址應該不會被人看到吧……


IE6瀏覽器也是支持的哦!是不是已經(jīng)有些jQuery的樣子啦!


7. 你怎么就一種姿勢啊,人家都膩了誒

循序漸進到現(xiàn)在,都是拿id來舉例的,實際應用,我們可能要使用類名啊,標簽名啊什么的,現(xiàn)在,為了接下來的繼續(xù),有必要支持多個“姿勢”。


在IE8+瀏覽器中,我們有選擇器API,document.querySelectordocument.querySelectorAll,前者返回唯一Node,后者為NodeList集合。大統(tǒng)一起見,我們使用后者。于是,就有:



var F = function(selector, context) {    return this.getNodeList(selector, context);};F.prototype.getNodeList = function(selector, context) {    context = context || document;    this.element = context.querySelectorAll(selector);    return this;};var $ = function(selector, context) {    return new F(selector, context);};


此時,我們就可以使用各種選擇器了,例如,$("body #image"), this.element就是選擇的元素們。


8. IE6/IE7腫么辦?

IE6/IE7不認識querySelectorAll,咋辦?


jQuery就使用了一個比較強大的選擇器框架-Sizzle. 知道就好,重在演示原理,因此,下面還是使用原生的選擇器API示意,故demo效果需要IE8+瀏覽器下查看。


8. 遍歷是個麻煩事

this.element此時類型是NodeList, 因此,直接this.element.style.xxx的做法一定是報錯,看來有必要循環(huán)下:



F.prototype.hide = function() {    var i=0, length = this.element.length;    for (; i<length; i+=1) {        this.element[i].style.display = "none";    }    };


于是乎:



$("img").hide();  // 頁面所有圖片都隱藏啦!


上面代碼的demo地址應該不會被人看到吧……


單純一個hide方法還可以應付,再來個show方法,豈不是還要循環(huán)遍歷一次,豈不是要煩死~


因此,急需一個遍歷包裝器元素的方法,姑且叫做each吧~


于是有:



F.prototype.each = function(fn) {    var i=0, length = this.element.length;    for (; i<length; i+=1) {        fn.call(this.element[i], i, this.element[i]);    }    return this;};F.prototype.hide = function() {    this.each(function() {       this.style.display = "none";    });};$("img").hide();  // 頁面所有圖片都隱藏啦!


上面代碼的demo地址應該不會被人看到吧……


9. 我不喜歡this.element, 可以去掉嗎?

現(xiàn)在包裝器對象結構類似這樣:



F.prototype = {    element: [NodeList],    each: function() {},    hide: function() {}}


element看上去好礙眼,就不能去掉嗎?可以啊,寶貝,NodeList是個類數(shù)組結構,我們把它以數(shù)值索引形式分配到對象中就好啦!一來去除冗余element屬性,二來讓原型對象成為類數(shù)組結構,可以有一些特殊的功能。


于是,F.prototype.getNodeList需要換一個名字了,比方說初始化init, 于是有:



F.prototype.init = function(selector, context) {    var nodeList = (context || document).querySelectorAll(selector);    this.length = nodeList.length;    for (var i=0; i<this.length; i+=1) {        this[i] = nodeList[i];        }    return this;};


此時,each方法中,就沒有煩人礙眼的this.element[i]出現(xiàn)了,而是直接的this[i].



F.prototype.each = function(fn) {    var i=0, length = this.length;    for (; i<length; i+=1) {        fn.call(this[i], i, this[i]);    }    return this;};


我們也可以直接使用索引訪問包裝器中的DOM元素。例如:$("img")[0]就是第一張圖片啦!


上面代碼的demo地址應該不會被人看到吧……


10. 我是完美主義者,我特不喜歡F名稱,可以換掉嗎?

F這個名稱從頭到尾出現(xiàn),我好不喜歡的來,我要換成$, 我就是要換成$符號……


這個……$已經(jīng)用了啊,再用沖突的吧。再說,你又不是狐后,耍無賴也沒用啊……




好吧,想想其他辦法吧。一步一步來,那我把所有的F換成$.fn.


就有:


上圖代碼的demo地址應該不會被人看到吧……


顯然,運行是OK的。似乎也非常有jQuery的模樣了,但是,實際上,跟jQuery比還是有差別的,有個較大的差別。如果是上圖代碼所示的JS結構,則包裝器對象要擴展新方法,每個都需要再寫一個原型的。例如,擴展一個attr方法,則要寫成:



$.fn.prototype.attr = function() {    // ...};


又看到prototype了,高級的東西應該要隱藏住,否則會給人難以上手的感覺。那該怎么辦呢?御姐不是好惹的。


腦子動一下就知道了,把F.prototype換成$.fn不久好了。這樣,擴展新方法的時候,直接就是


$.fn.attr = function() {    // ...};


至此,就使用上講,與jQuery非常接近了。

但是,還有幾個F怎么辦呢,總不能就像下面這樣放著吧:
var $ = function(selector, context) {    return new F(selector, context);};var F = function(selector, context) {    return this.init(selector, context);};$.fn = F.prototype;$.fn.init = function(selector, context) {    // ...    return this;};$.fn.each = function(fn) {   // ...};$.fn.hide = function() {   // ...};


數(shù)學中,我們都學過合并同類項。仔細觀察上面的的代碼:

$()返回的是new F(),而new F()又是返回的對象的引用。擦,這返回來返回去的,參數(shù)又是一樣的,我們是不是可以一次性返回,然后再做些手腳,讓$.fn.init返回的this依然能夠正確指向。


于是,一番調(diào)整有:



var $ = function(selector, context) {    return new $.fn.init(selector, context);};var F = function() { };$.fn = F.prototype;$.fn.init = function(selector, context) {    // ...    return this;};// ...


上面代碼顯然是有問題的,new的是$.fn.init, $.fn.init的返回值是this. 也就是$()的返回值是$.fn.init的原型對象,尼瑪$.fn.initprototype原型現(xiàn)在就是個光桿司令啊,喲,正好,$.fn對應的原型方法,除了init沒用外,其他hide(), each()就是我們需要的。因此,我們需要加上這么一行:



$.fn.init.prototype = $.fn


于是,$()的返回值從$.fn.init.prototype一下子變成$.fn,正好就是我們一開始的擴展方法。


于是乎,大功告成。慢著……


上面明明還有殘留的F呢!


哦,那個啊。F是任意函數(shù),$本身就是函數(shù),因此,直接使用$替換就可以了:



var $ = function(selector, context) {    return new $.fn.init(selector, context);};var F = function() { };   // 這個直接刪除$.fn = $.prototype;$.fn.init = function(selector, context) {    // ...    return this;};// ...


上圖代碼的demo地址應該不會被人看到吧……


實際上,如果你不是非得一個$行便天下的話,到了上面進階第9步就足夠了。jQuery在第10步的處理是為了彰顯其$用得如此的出神入化,代碼完美,令人驚嘆!


至此,jQuery大核心已經(jīng)一步一步走完了,可以看到,所有的這些進階都是根據(jù)需求、實際開發(fā)需要來的,慢慢完善,慢慢擴充的!


11. 每個擴展方法都要$.fn.xxxx, 好鬧心的來



$.fn.css = function() {}$.fn.attr = function() {}$.fn.data = function() {}// ...


每個擴展前面都有個$.fn, 好討厭的感覺,就不能合并嗎?


于是,jQuery搞了個extend方法。



$.fn.extend({    css: function() {},    attr: function() {},    data: function() {},    // ...});


12. $()不僅可以是選擇器字符串,還可以是DOM

init方法中,判斷第一個參數(shù),如果是節(jié)點,直接this[0] = this_node. over!


以下13~?都是完善啊,補充啊,兼容性處理啊什么的,沒有價值,到此為止!


三、排了很長隊的結束語


網(wǎng)上也有其他一些介紹jQuery原理或機制的文章,可能當事人自己理解,而閱讀者本來就不懂,說來說去,越說越繞,可能更不懂了。


jQuery是很優(yōu)秀,好比身為靈長類的人類。但是,其誕生顯然是從簡單開始的。因此,要了解人類,可以通過追溯其起源。如果你是上帝,要讓你造一個人,你會怎么造,是一口氣出來?女媧造人還要捏泥人呢!不妨從單細胞生物開始,隨著自然進化,淘汰,自然而然,就會出現(xiàn)人類,上帝他就是這么干的。


jQuery的誕生也大致如此,要想了解jQuery,可以試試踏著本文jQuery的成長足跡,一點一點逐步深入,您就會了解為何jQuery要這么設計,它是如何設計的等。


雖然,內(nèi)容由淺及深,但是,其中涉及的原型以及new構造函數(shù)的一些特性,對于新人而言,還是有一些理解門檻的,希望我的描述與解釋可以讓你有一絲豁然開朗,那就再好不過了。


感謝您的閱讀至此,歡迎指出文章可能書寫不準確的地方,再次感謝!


月底在百姓網(wǎng)有個小分享,演示文檔連個肉渣子還沒準備呢。因此,未來一周休文。


原創(chuàng)文章,轉載請注明來自張鑫旭-鑫空間-鑫生活[http://www.zhangxinxu.com]

本文地址:http://www.zhangxinxu.com/wordpress/?p=3520


(本篇完)


如果您覺得本文的內(nèi)容對您的學習有所幫助:


               

分享到:







7





               

標簽: , , , , , , ,




這篇文章發(fā)布于 2013年07月17日,星期三,22:57,歸類于 jquery相關。                        閱讀 21555 次, 今日 37 次



  
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
圖靈社區(qū) : 閱讀 : OOP與jQuery(四):函數(shù)作用域、方法連綴及jQuery.fn
$到底是什么
jquery 原型
3. 構造jQuery對象
jQuery是怎樣工作的
jQuery.fn和jQuery.prototype區(qū)別介紹
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服