jQuery原始碼初探(3)

2021-07-30 12:23:56 字數 3617 閱讀 3997

今天我們先來 聊聊 jquery 中的無 new 構造

寫過 js 物件導向的同學知道,一般我們是這麼來寫的

//建構函式

function

myjquery

() //方法掛載到原型上

myjquery.prototype.say = function

() var myjquery = new myjquery(); // 例項化

console.log( myjquery.age ); // 20

console.log( myjquery.say() ); // my age is 20

這是一種比較常見的寫法,然而 jquery 並不是這麼做的,回想一下,我們平時在用 jquery 獲取元素的時候,經常都是$('#myid') , $('.myclass')這種方式去呼叫的,難道說 jquery 不用 new 去建立乙個例項?

其實不然,jquery 內部也是用 new 建立乙個 jquery 物件 , 只不過用的十分巧妙, 接下來我們來看看jquery是怎麼做到的!

在 jquery 原始碼中有這麼一段

jquery = function

( selector, context )

這個就是 jquery 的入口方法 , 它返回的 是乙個new jquery.fn.init( selector, context );我們知道, 用 new 乙個物件 ,肯定是返回乙個物件的例項,那麼也就是返回的是jquery.fn.init( selector, context )的例項,那麼這個jquery.fn又是什麼? 我們檢視原始碼中有這麼一段:

jquery.fn = jquery.prototype =
也就是說,jquery.fn就是jquery建構函式的原型。

接著我們看看jquery.fn.init()這個方法,原始碼中可以找到是這麼寫的:

init = jquery.fn.init = function( selector, context, root )
有的同學可能認為到這裡就結束了,是嗎?ok,我們來測試一下,我們把上面我們的**改造跟 jquery 一樣結構,

var myjquery = function

() myjquery.fn = myjquery.prototype= ,

age : 20,

say : function

() }

myjquery().age; //'undefiend'

myjquery().say();

// 'uncaught typeerror: myjquery(...).say is not a function'

什麼?出錯了,沒錯,得到的結果確實 令人意外 , 不過也是意料之中 , 我們稍加分析一下就知道了。

上面**我們使用了return new myjquery.fn.init();

返回的是 myjquery 原型上的 init() 方法的例項 , 我們在發現在 init() 方法中返回了this ; 此時的 this 指向的是myjquery.fn.init的例項,

呼叫myjquery() 得到的結果是myjquery.fn.init 的例項

而在myjquery.prototype.init內部中根本就沒有 age 屬性 和 say 方法, 所以此時通過這個結果訪問不到 myjquery.prototype 的屬性 和方法的 , 因此上面得到的結果也就 不意外了。

可是我們用 jquery 為什麼沒有出現這樣的情況呢?原來我們還少了一句關鍵的**, jquery 中是這麼寫的:

init.prototype = jquery.fn

;

我們在上面就看到了init = jquery.fn.init,所以說這句**相當於

jquery.fn

.init

.prototype = jquery.fn

;

這句話是關鍵,現在我們可以發現:

jquery.fn

.init

.prototype = jquery.fn = jquery.prototype

;

通過原型傳遞來解決上面的問題,把jquery的原型傳遞給

jquery.prototype.init.prototype

也就是說 jquery 的原型物件 覆蓋了內部 init 構造器的原型物件。

這樣new init 的出來的例項物件也就等價於new jquery的例項物件,所以也就可以訪問jquery的原型方法了。

我們把這句話加上去,把上面的函式改寫成:

var myjquery = function

() myjquery.fn = myjquery.prototype= ,

age : 20,

say : function

() }

myjquery.prototype.init.prototype = myjquery.prototype;

myjquery().age; //20

myjquery().say() //20

世界清靜多了,不是麼?

ok,這就是 jquery 實現無 new 操作的 原理 ~

上面還有一點點東西,我們補充一下:

1. 我們看到 jquery 物件的是通過原型中的 init 方法 return 回來的,如下:

return

new jquery.fn.init( selector, context );

也就是說,我們每次呼叫 jquery 的時候去 new 乙個新的物件 , 因此,我們在寫**的時候,如果頻繁使用乙個 jquery 物件的話,我們不妨把它用乙個變數存起來,可以避免每次去建立物件~

2. 上面 jquery 原型上,我單獨拿出來一句:

constructor: jquery

jquery 這麼做是為了保證 constructor 的指向,防止建構函式指向錯誤,引起呼叫的問題。那麼為什麼會產生這樣的問題呢?

//方式一

fn.prototype.say = function

(){}

//方式二

fn.prototype =

}

jquery 採用的是 第二種 方式,這種方式與第一種方式差別很大,第一種是給原型新增乙個方法,這種方式是不會影響fn原型內部 constructor 的指向問題,而第二種方式是重寫原型, 相當於原型覆蓋,原來的原型已不復存在,所以需要重新定義 constructor 的指向,小夥伴們以後寫**的時候多注意一點~

OkHttp原始碼初探

在之前的文章我中我們介紹了okhttp的基本使用方法並簡單說明了原始碼下各個module的功能作用,從這篇開始我們將要開始分析okhttp的原始碼。首先,我們先來回憶一下okhttp的使用過程 1.建立乙個okhttpclient物件 2.建立乙個request物件 3.呼叫okhttpclient...

RequireJS原始碼初探

前兩天跟著葉小釵的部落格,看了下requirejs的原始碼,大體了解了其中的執行過程。不過在何時進行依賴項的載入,以及具體的 在何處執行,還沒有搞透徹,奈何能力不夠,只能先記錄一下了。看原始碼從頭開始看,肯定是不切實際的。按照葉小釵的方法,是從data main開始的,所以我們也從那裡開始把!首先,...

RequireJS原始碼初探

前兩天跟著葉小釵的部落格,看了下requirejs的原始碼,大體了解了其中的執行過程。不過在何時進行依賴項的載入,以及具體的 在何處執行,還沒有搞透徹,奈何能力不夠,只能先記錄一下了。看原始碼從頭開始看,肯定是不切實際的。按照葉小釵的方法,是從data main開始的,所以我們也從那裡開始把!首先,...