久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

jQuery誕生記

 風(fēng)之飛雪 2014-03-14

by zhangxinxu from http://www.

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


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


我大學(xué)時(shí)候在圖書館翻過一本很破舊的書,,講生物理論的,,主要內(nèi)容就是探討生命的產(chǎn)生是偶然還是必然。里面很多亞里士多德都看不懂的公式計(jì)算什么的,還有模擬原始地球環(huán)境出現(xiàn)了有機(jī)物的實(shí)驗(yàn)什么的 ,??傊瑫撌龅挠^點(diǎn)是:“在當(dāng)時(shí)的地球環(huán)境下,,生命的產(chǎn)生是必然的,!” 無數(shù)次機(jī)會的偶然條件、無數(shù)次化合物的相遇反應(yīng)等必定會產(chǎn)生有機(jī)物,,再有N多偶然,,有機(jī)物必然形成了有機(jī)體……


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


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


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


刀削面機(jī)器人


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


1. gelElementById太長了

頁面上有個(gè)按鈕,還有個(gè)圖片,,我想點(diǎn)擊按鈕圖片隱藏,,如下HTML:



<button id="button">點(diǎn)擊我</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名稱長且重復(fù)出現(xiàn),好像到了公司發(fā)現(xiàn)卡沒帶又回家重新拿卡的感覺,,我希望越簡單越好,。恩,, 我很喜歡錢,$這個(gè)符號我很喜歡,,我打算改造一番,簡化我的工作:



var $ = function(id) {
    return document.getElementById(id);
};

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


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


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

后來頁面復(fù)雜了,,點(diǎn)擊一個(gè)按鈕,,有2張圖片要隱藏。



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


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


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


就是要變成下面的效果:



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


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

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


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



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


上面代碼的demo地址應(yīng)該不會被人看到吧……


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


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


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

雖IE6~IE8不識HTMLElement原型擴(kuò)展,,但是,,Function的原型擴(kuò)展其認(rèn)識啊。管不管用,,暫時(shí)不得而知,,先隨便搞個(gè)簡單的試試唄~



var F = function() {};
F.prototype.hide = function() {
    this?.style.display = "none";
};

new F().hide();    // 這個(gè)實(shí)現(xiàn)隱藏?


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


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


很傻很天真


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



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


舉例說明:



var F = function(id) {
    return document.getElementById(id);
};

new F("image1") == document.getElementById("image1");    // true 說明看上去返回DOM對象,,實(shí)際確實(shí)就是DOM對象



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

new F("image1") == "image1";    // false 說明看上去返回字符串值,,實(shí)際并不是字符串


回到上面天真的想法,。要想使用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地址應(yīng)該不會被人看到吧……


5. 我不喜歡太暴露

F()中的this.element實(shí)際上將element這個(gè)屬性直接暴露在了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呢,?大家務(wù)必擦亮眼睛,F.prototype.getElementById的返回值是this,,也就是new F()的返回值是this. 形象點(diǎn)就是new F("image")出了一拳,,又反彈到自己臉上了。


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


上面代碼的demo地址應(yīng)該不會被人看到吧……


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

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


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



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


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



$("image").hide();


上面代碼的demo地址應(yīng)該不會被人看到吧……


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


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

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


在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);
};


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


8. IE6/IE7腫么辦,?

IE6/IE7不認(rèn)識querySelectorAll,咋辦,?

怎么辦,?


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


8. 遍歷是個(gè)麻煩事

this.element此時(shí)類型是NodeList, 因此,,直接this.element.style.xxx的做法一定是報(bào)錯,,看來有必要循環(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地址應(yīng)該不會被人看到吧……


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


因此,,急需一個(gè)遍歷包裝器元素的方法,,姑且叫做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地址應(yīng)該不會被人看到吧……


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

現(xiàn)在包裝器對象結(jié)構(gòu)類似這樣:



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


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


于是,F.prototype.getNodeList需要換一個(gè)名字了,,比方說初始化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;
};


此時(shí),,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地址應(yīng)該不會被人看到吧……


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

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


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


狐后耍無賴


御姐發(fā)飆了


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


就有:

所有的F換成$.fn之后~


上圖代碼的demo地址應(yīng)該不會被人看到吧……


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



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


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


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


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


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

但是,還有幾個(gè)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ù)學(xué)中,,我們都學(xué)過合并同類項(xiàng)。仔細(xì)觀察上面的的代碼:

$()返回的是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)在就是個(gè)光桿司令啊,,喲,正好,,$.fn對應(yīng)的原型方法,,除了init沒用外,其他hide(), each()就是我們需要的,。因此,,我們需要加上這么一行:



$.fn.init.prototype = $.fn


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


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

慢著……


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


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



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

// ...


上圖代碼的demo地址應(yīng)該不會被人看到吧……


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


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


11. 每個(gè)擴(kuò)展方法都要$.fn.xxxx, 好鬧心的來



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


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


于是,jQuery搞了個(gè)extend方法,。



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


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

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


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


三,、排了很長隊(duì)的結(jié)束語


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


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


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


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


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


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


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

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


(本篇完)


如果您覺得本文的內(nèi)容對您的學(xué)習(xí)有所幫助:支付鼓勵


               

分享到:







7





               

標(biāo)簽: , , , , , , ,




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



  

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多