本來只是一個自己學(xué)習(xí)jQuery筆記的簡單分享,沒想到獲得這么多人賞識。我自己也是傻呵呵的一臉迷茫,感覺到受寵若驚。

不過還是有人向批判我的文章說,這是基本知識點,完全跟jQuery源碼沾不上邊。說jQuery博大精深,還要我靜下心來研究, 別凈整些沒用的。弄的我一臉懵逼,WTF?我從頭到尾都沒有說我講的多高端,我連標(biāo)題都寫的“淺談”。就完全不能讓我等菜鳥慢慢先從的簡單的入手嗎?

但是有位名為“萌新”三好童鞋,就做的非常好。“啪”!,反手就是一拖鞋留言砸過來一串代碼。指出說undefined在ES5、ES6標(biāo)準(zhǔn)中只是全局作用域下不能被定義,一旦脫離全局作用域下undefined就能夠被定義。

所以希望能夠像能夠像萌新同學(xué)狠狠打臉找知識點錯誤,而不是指出我這個太簡單一類的。這個我本來就是個人學(xué)習(xí)過程的淺談一下,給菜鳥一點活路嗎!

原型prototype

我們創(chuàng)建的每個函數(shù)都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。
--《高級程序第三版》-6.23 原型模式

這里我引用了高級程序第三版當(dāng)中的一段話用來簡單描述原型prototype,但是這個玩意具體有什么用?
解釋何為原型之前, ?先看下?的代碼:

     //創(chuàng)建一個構(gòu)造函數(shù)
    function Person() {        this.sayHello = function() {            console.log('Hello,I am one Dog')
        }
    }    //創(chuàng)建兩個對象
    var dog1 = new Person(),
        dog2 = new Person();    //兩個實例對象進行比較
    dog1.sayHello();
    dog2.sayHello();    console.log("dog1.sayHello === dog2.sayHello的結(jié)果是:" + (dog1.sayHello === dog2.sayHello));

控制臺輸出結(jié)果:

這里dog1,dog2都是構(gòu)造函數(shù)Person的實例,但是兩個人的sayHello方法并不完全相等。也就是說dog1和dog2分別在自己所屬空間開辟了一塊內(nèi)存。

夭壽啦!單身狗為何不報團取暖,不是說好一起相親相愛嗎!不是說好一起共享種子,一起開黑嗎?月黑風(fēng)高秋名山一起開車嗎!

所以為了避免原本每天遭受狗糧侵蝕單身汪繼續(xù)團結(jié)一致,這個時候原型prototype就起到很好的穩(wěn)定dog群內(nèi)團結(jié)的作用。

    //創(chuàng)建一個構(gòu)造函數(shù)
    function Person(){};
    Person.prototype.sayHello = function(){        console.log("Hello, I am one Dog")
    }    
    //創(chuàng)建兩個對象
    var dog1 = new Person(),
        dog2 = new Person();    
    //兩個實例對象進行比較
    dog1.sayHello();
    dog2.sayHello();    console.log("dog1.sayHello === dog2.sayHello的結(jié)果是:"+ (dog1.sayHello === dog2.sayHello));

控制臺輸出結(jié)果:

說明此時兩名單身狗又團結(jié)一致,資源共享sayHello方法。而不是每個私自建立一個空間,去存放sayHello方法。

當(dāng)實例對象需要尋找sayHello方法的時候,就會先去構(gòu)造函數(shù)Person函數(shù)當(dāng)中尋找sayHello方法,然后Person函數(shù)方法當(dāng)中沒有找到,就會去Person的原型當(dāng)中去找sayHello方法。(同理在JavaScript當(dāng)中,如果創(chuàng)建多個對象,但是卻只共享一個方法。減少了內(nèi)存的使用,能夠優(yōu)化性能不少。)

而jQuery里面也充斥不少原型prototype,所以看下面jQuery代碼,就會知道相應(yīng)查找順序了,同樣也能更好的理解后面的代碼。

jQuery無new構(gòu)造

之前第一章,我們有講過jquery通過如下代碼來暴露接口:

window.jquery = window.$ = jQuery

舉個栗子:

$("#box")   =  jQuery("#box")

那么jQuery這個函數(shù)開始執(zhí)行,此時讓我們打開jQuery源碼,看看jQuery內(nèi)部是如何實現(xiàn)的。

(function(window, undefined) {
    var
    // ...
    jQuery = function(selector, context) {
        return new jQuery.fn.init(selector, context, rootjQuery);
    },

    jQuery.fn = jQuery.prototype = {
        init: function(selector, context, rootjQuery) {
            // ...
        }
    }
    jQuery.fn.init.prototype = jQuery.fn;

})(window);

估計有童鞋 jQuery.fn.init.prototype = jQuery.fn 這一句都會被卡主,滿臉黑人問號。但是這句真的算是 jQuery 的絕妙之處。理解這幾句很重要,分別解析一下:


(來自靈魂抽象派畫師-車大棒)

1、首先要明確,使用 $(‘xxx’) 這種實例化方式,其內(nèi)部調(diào)用的是return new jQuery.fn.init(selector, context, rootjQuery) 這一句話,也就是構(gòu)造實例是交給了 jQuery.fn.init() 方法取完成。

2、將jQuery.fn.init 的 prototype 屬性設(shè)置為jQuery.fn,那么使用 new jQuery.fn.init() 生成的對象的原型對象就是jQuery.fn ,所以掛載到 jQuery.fn 上面的函數(shù)就相當(dāng)于掛載到 jQuery.fn.init()生成的 jQuery 對象上,所有使用new jQuery.fn.init()生成的對象也能夠訪問到 jQuery.fn 上的所有原型方法。

3、也就是實例化方法存在這么一個關(guān)系鏈
jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;
new jQuery.fn.init()相當(dāng)于 new jQuery() ;
jQuery()返回的是 new jQuery.fn.init(),而 var obj = new jQuery(),所以這 2 者是相當(dāng)?shù)?,所以我們可以無 new 實例化 jQuery 對象。

-------來自某博客大牛的小結(jié)(看到好多博客上面都有,不清楚誰才是原創(chuàng))

PS:
原本這里打算把曬上我用思維箭頭圖畫出個整個結(jié)構(gòu)之后,就基本上一句話可以帶過了。但是我看到別人博客上這一段總結(jié)很好,所以就直接引用了。當(dāng)然寫博客的時候,我就料到直接引用可能會有點影響不好。修改一下,然后用自己語言來說,可能會效果好的多。

但是完全覺得沒有必要, 好東西我覺得就應(yīng)該直接拿出來分享。事實上我本來的學(xué)習(xí)jQuery源碼就是吸收各種視頻資源,以及各路大牛博客去學(xué)習(xí)參考。別人寫的好,寫的詳細這就是無可厚非的。(如果有原話博客主,對我私自引用有意見。留言,我立刻刪或者改。)

jQuery的鏈?zhǔn)秸{(diào)用

早在第一次接觸jQuery的時候,就被它風(fēng)騷的鏈?zhǔn)秸{(diào)用給吸引了,感覺操作真TMD的6到飛起。
例如:$('div').eq(0).show().end().eq(1).hide();

所以希望待會簡單的談及這個知識點之后,我不希望你們來一句:“大神,這波操作666?。 ?/strong>,而是高呼道:“what?這么簡單!”(PS:大牛們請無視這句話,還有不懂這兩句話差別的也請無視這句話?。?/p>

var oneDog = {
        food : function(){            console.log("今天晚餐是泡面和一個鹵雞蛋!");            return this;    
        },
        sad : function(){            console.log("坐地鐵被喂了十幾站的狗糧!");            return this;
        },
        game : function(){            console.log("今天DOTA2開黑10連跪");            return this;
        },
    }
    
    oneDog.food().sad().game();       //沒錯,這樣就是實現(xiàn)了鏈?zhǔn)秸{(diào)用。

然后控制臺就能夠依次輸出每個方法當(dāng)中的log語句,就是這么簡單每次調(diào)用返回它自己本身就可以形成一個鏈?zhǔn)秸{(diào)用。(來!開始喊那句話吧?。?/p>

看過前面的小demo之后,讓我們回過頭來看jQuery的源碼是如何實現(xiàn)鏈?zhǔn)秸{(diào)用。
首先第一步,顯示HTML骨架部分:

    <div>我是dog1</div>
    <div>我是dog2</div>

接下來就是jQuery代碼

console.log($(''div').eq(0))

這個時候控制臺輸出結(jié)果:

之后在eq(0)后面緊緊跟end()結(jié)束的時候,然后相當(dāng)于整個代碼返回給prevObject這個集合了:

//jQuery源碼當(dāng)中的end函數(shù)end: function() {        return this.prevObject || this.constructor(null);
    }

總的來說,

1、eq(i) 之后留下prevObject 屬性,這個屬性記錄了操作的 jQuery 對象集合;

2、當(dāng)我們在鏈?zhǔn)秸{(diào)用 end() 方法后,內(nèi)部就返回當(dāng)前 jQuery 對象的 prevObject 屬性,完成回溯。

3、和前面我們返回的this的小demo,有異曲同工之妙。

小結(jié):

今天將的知識點比較少,先是帶大家回顧了prototype知識點,之后淺談了一下jQuery的無new的構(gòu)造結(jié)構(gòu),以及鏈?zhǔn)秸{(diào)用的原理。

兩篇博客所講的知識完全沒有一些知名大牛博客一篇博客講的知識點多,但是哪怕能講懂一個點我也會很欣慰。有句話說的好:
不積跬步,無以至千里;不積小流,無以成江海。

原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,再次再次再次歡迎各位啪啪啪的打臉賜教。(有句話說的好,重要的詞得說三遍。)

http://www.cnblogs.com/chedabang/p/6649473.html