JQ對象到底是什么

jQuery對象是什么,舉個例子,$('#id')?返回的就是jQuery對象,這個東西是整個jQuery的核心所在,所以我先來分析它。

var?jQuery = function( selector, context ) {

????// The jQuery object is actually just the init constructor 'enhanced'

????return?new?jQuery.fn.init( selector, context, rootjQuery );

};

......

jQuery.fn = jQuery.prototype = {

????constructor: jQuery,

????init: function( selector, context, rootjQuery ),

????selector: "",

????jquery: "1.7.2",

????length: 0,

????size: function(),

????toArray: function(),

????get: function( num ),

????pushStack: function( elems, name, selector ),

????each: function( callback, args ),

????ready: function( fn ),

????eq: function( i ),

????first: function(),

????last: function(),

????slice: function(),

????map: function( callback ),

????end: function(),

????push: push,

????sort: [].sort,

????splice: [].splice

};

jQuery.fn.init.prototype = jQuery.fn;

?

?

我敢說,第一次看到這段代碼的人都會被它的結構搞暈,因為這種寫法實在是太罕見了。關于john的想法,我斗膽一猜:

1. jQ對象的構造函數為啥是protptype.init

答:構造函數中的邏輯和prototype的其他?屬性/方法?有聯系,比如?selector?和?length,寫在一起比較易讀。

調用init?方法時,如果參數為空,jQ對象可以等同于?prototype,這樣看起來結構很清晰;

如果參數不為空,會覆蓋一些?prototype?的屬性(如?selector?和?length,也就說prototype?上的屬性只是為了給一個默認值而已),還會創建一些?prototype?上沒有列出的屬性(如context),這些屬性本該寫在構造函數中的。但同樣的,為了讓邏輯保持緊湊,就一并寫在?init?方法中。

?


2. jQ到底想創建一個怎樣的對象?
答:這個對象有點像數組,比如下面這段代碼:

?

function?FuckYou(who) {

????this[0] = who;

}

var?fy = new?FuckYou('john');

于是?fy[0] === 'john',是不是有點小暈了?千萬搞清楚,這不是數組,別被你的眼睛蒙蔽了,這是一個對象,0是它的屬性名而已。因為this.0 = who?會語法報錯,所以就用了一個小技巧。


再看prototype?中的其他方法,如each, slice, map, push, sort, splice,無一不是在模擬數組。

?

3.?解釋一下pushStack唄?

答:顧名思義,就是一個壓棧操作,主要是用于undo

?

?

pushStack: function( elems, name, selector ) {

????//?創建一個全新的jQ對象,API和prototype一模一樣

????var?ret = this.constructor();

?

????// elems?是數組,直接push

????if?( jQuery.isArray( elems ) ) {

????????push.apply( ret, elems );

?

????// elems?是類數組,調用merge(),這存在兩種情況:

????// 1. elems是childNodes這樣的類數組

????// 2. elems是this[0], this[1]這樣的模擬數組,上面舉過例子的

????} else?{

????????jQuery.merge( ret, elems );

????}

?

????//?如?$("p").find("span")

????//?第一次是匹配p,第二次是在上次的結果中匹配span

????//?類似這樣破壞上一個鏈的行為,jQ都會把上一個鏈存起來,以便回退(調用end())

????ret.prevObject = this;

?

????ret.context = this.context;

?

????//?這小段很有意思,從這里你幾乎可以看出整個jQ的設計思想

????// name?表示一個方法名

????// selector?表示 選擇器

????//?你懂的,jQ里面有很多DOM相關的方法,比如after, find之類的,它們的參數就是一個選擇器

????if?( name === "find"?) {

????????// find?相當于后代選擇器,如?"div span"?這樣的

????????ret.selector = this.selector + ( this.selector ? " "?: ""?) + selector;

????} else?if?( name ) {

????????//?這個分支比較復雜,光看這里的代碼是看不懂的

????????//?我就一直為什么要加?.?因為除了匹配class,是用不到?.?的

????????//?我覺得吧,這個應該涉及到?Sizzle?的匹配模式問題,我不關心這種細節問題,囧

????????ret.selector = this.selector + "."?+ name + "("?+ selector + ")";

????}

?

????return?ret;

}

?

4.?再解釋一下?init??

:?必須解釋啊,這個方法真是重中之重,jQ的構造函數不解釋還能解釋啥。

init: function( selector, context, rootjQuery ) {

????var?match, elem, ret, doc;

?

????//?處理?$(""), $(null), or $(undefined)

????if?( !selector ) {

????????return?this;

????}

?

????//?處理?$(DOMElement)

????if?( selector.nodeType ) {

????????this.context = this[0] = selector;

????????this.length = 1;

????????return?this;

????}

?

????//?因為?body?元素只有一個,所以可以優化一下

????if?( selector === "body"?&& !context && document.body ) {

????????this.context = document;

????????this[0] = document.body;

????????this.selector = selector;

????????this.length = 1;

????????return?this;

????}

?

????//?處理?HTML?字符串

????if?( typeof?selector === "string"?) {

????????//?如果是標簽,如

,可省略第二個分支的正則匹配

????????if?( selector.charAt(0) === "<"?&& selector.charAt( selector.length - 1 ) === ">"?&& selector.length >= 3 ) {

????????????match = [ null, selector, null?];

?

????????} else?{

????????????// quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/

????????????//?再來看早期的一個版本

????????????// quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/

????????????//

????????????//?大同小異,但前者肯定是做了更多的考慮,

????????????//?比如防止通過location.hash?進行XSS攻擊

????????????//

????????????//?這個正則有點復雜,它分為兩個分支

????????????// 1. ^[^#<]*(<[\w\W]+>)[^>]*$

????????????// 2. ^#([\w\-]*)$

????????????//?第二個不用說,是匹配ID的

????????????//?第一個用來匹配HTML代碼段:

????????????//???[^#<]*?表示開頭不能包含#和<</span>

????????????//???(<[\w\W]+>)?表示匹配完整的標簽,如

123

????????????//???[^>]*$?表示結尾不能包含>

????????????match = quickExpr.exec( selector );

????????}

?

????????//?匹配成功,并且匹配上ID時沒有指定context

????????//?為什么?ID?和context?不能同時指定?拜托,ID全局唯一的好不

????????if?( match && (match[1] || !context) ) {

?

????????????//?處理?$(html) -> $(array)

????????????if?( match[1] ) {

????????????????//?確保?context?是一個?HTMLElement

????????????????context = context instanceof?jQuery ? context[0] : context;

????????????????//?確保?doc?是?document

????????????????doc = ( context ? context.ownerDocument || context : document );

?

????????????????// rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/

????????????????//?就是匹配單個標簽,如?或

????????????????//?如果匹配成功,不用往下走了,直接?createElement_x?就完事

????????????????ret = rsingleTag.exec( selector );

?

????????????????if?( ret ) {

????????????????????//?我凌亂了,context?可能是純對象么?

????????????????????//?按第一個分支的邏輯,context應該是?{id: 'id', title: 'title'}之類的

????????????????????if?( jQuery.isPlainObject( context ) ) {

????????????????????????selector = [ document.createElement_x( ret[1] ) ];

????????????????????????jQuery.fn.attr.call( selector, context, true?);

?

????????????????????} else?{

????????????????????????selector = [ doc.createElement_x( ret[1] ) ];

????????????????????}

?

????????????????} else?{

????????????????????//?不是單個標簽,就創建文檔碎片吧

????????????????????ret = jQuery.buildFragment( [ match[1] ], [ doc ] );

????????????????????selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;

????????????????}

?

????????????????return?jQuery.merge( this, selector );

?

????????????//?處理$("#id")

????????????} else?{

????????????????elem = document.getElementByIdx_x( match[2] );

?

????????????????// Check parentNode to catch when Blackberry 4.6 returns

????????????????// nodes that are no longer in the document #6963

????????????????//?囧,黑莓還有這種問題,我覺得移動開發就該另寫一個庫,不能把所有bugfix都寫在jQ里

????????????????//?就像說,難道移動開發還要考慮IE678??肯定不要啊,基本都支持HTML5了

????????????????//?既然這樣,那又何必在這fix手機瀏覽器呢?john?您蛋疼了么

????????????????if?( elem && elem.parentNode ) {

????????????????????// IE?和?Opera?調用?getElementById?會依據name返回,而不是ID,再囧

????????????????????if?( elem.id !== match[2] ) {

????????????????????????return?rootjQuery.find( selector );

????????????????????}

?

????????????????????// Otherwise, we inject the element directly into the jQuery object

????????????????????this.length = 1;

????????????????????this[0] = elem;

????????????????}

?

????????????????this.context = document;

????????????????this.selector = selector;

????????????????return?this;

????????????}

?

????????//?處理?$(expr, $(...)),相當于?$(...).find(expr)

????????//?這么傳參數的人純屬蛋疼,jQ就是這樣被搞大的

????????//?反正我覺得接口就該定死,context只能傳?HTMLElement?或 選擇器

????????//?搞得我現在覺得jQ的接口好像萬能一樣,啥都能傳

????????} else?if?( !context || context.jquery ) {

????????????return?( context || rootjQuery ).find( selector );

?

????????//?處理?$(expr, context),也相當于$(context).find(expr)

????????//?同樣蛋疼的寫法

????????} else?{

????????????return?this.constructor( context ).find( selector );

????????}

?

????//?處理?$(function)

????//?就是文檔加載完成時調用的函數

????} else?if?( jQuery.isFunction( selector ) ) {

????????return?rootjQuery.ready( selector );

????}

?

????// selector?是一個jQ對象,我真心覺得除了蛋疼沒有別的理由這么寫了

????if?( selector.selector !== undefined ) {

????????this.selector = selector.selector;

????????this.context = selector.context;

????}

?

????//?把?selector?加到?this?的尾部

????//?因為能走到這,this已經是一個類數組了

????return?jQuery.makeArray( selector, this?);

}

?

5.?還有啥想說的不?

答:最后提一點吧:

?

jQuery.fn = jQuery.prototype = {...}

jQuery.fn.init.prototype = jQuery.fn;

為啥要這么寫?比如第一行,為什么不直接賦給一個變量,而是賦給jQuery.fn?

1.?賦給一個變量就只能在jQ這個文件內部用,而jQ是有強大的插件機制的,所以為了便于外部擴展,賦給jQuery.fn。當然不處理這部分也沒事,您就多打幾個字,但是jQ畢竟是一個超級流行的框架,能縮寫的就自己縮了吧,省的別人去做這種無畏的勞動。

?

2.?第二行的寫法更加讓人蛋疼。首先?init?是構造函數,還要我繼續說?好吧,雖然我覺得這都是基礎知識了。

?

1

2

3

4

function?jQuery() { }

jQuery.prototype = {

????constructor: jQuery

}

如果jQ不寫這一行,之后?obj instanceof jQuery?就永遠為?false。

?

技巧:

1.?對象上的?屬性/方法?會覆蓋原型上對應的?屬性/方法(說?override?可能好些);

2.?巧用數組的方法,如下:

?

1

2

3

4

5

6

7

8

9

10

11

var?push = Array.prototype.push;

?

function?ArrayLike() {

????this[0] = 0;

????this[1] = 1;

????this.length = 2;

}

?

var?al = new?ArrayLike();

push.apply(al, [2, 3]);

console.log(al)

最后的結果是?al.length === 4,現在知道jQ對象為啥需要?length?屬性了吧

轉載于:https://www.cnblogs.com/galal/p/6027125.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254046.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254046.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254046.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

15、iOS開發之duplicate symbols for architecture x86_64錯誤

1. 錯誤提示 2. 分析錯誤原因 3. 解決問題辦法 一、錯誤提示 在我們寫代碼過程中可能會經常遇到這樣一個錯誤&#xff1a; [objc] view plaincopy print?<span style"font-size:32px;color:#ff0000;">ld: 4 duplicate symbols for architecture x86_64 clang…

【死磕Java并發】----- 死磕 Java 并發精品合集

【死磕 Java 并發】系列是 LZ 在 2017 年寫的第一個死磕系列&#xff0c;一直沒有做一個合集&#xff0c;這篇博客則是將整個系列做一個概覽。 先來一個總覽圖&#xff1a; 【高清圖&#xff0c;請關注“Java技術驛站”公眾號&#xff0c;回復&#xff1a;腦圖JUC】 【死磕Java…

vs官方使用教程中文版與英文版

Visual Studio IDE 中文文檔 https://docs.microsoft.com/zh-cn/visualstudio/ide/ Visual Studio IDE documentation https://docs.microsoft.com/en-us/visualstudio/ide/

linux subsys_initcall

宏定義__define_initcall(level,fn)對于內核的初始化很重要&#xff0c;他指示編譯器在編譯的時候&#xff0c;將一系列初始化函數的起始地址值按照一定的順序放在一個section中。在內核初始化段&#xff0c;do_initcalls() 將按順序從該section中以函數指針的形式取出這些函數…

vue transition

Vue.js 教程 (9) : 過渡動畫 Vue.js 提供非常簡單的過渡動畫接口。這些過渡動畫在 Vue.js 將目標元素插入或移除出 DOM 的時候會自動執行。能夠觸發動畫的指令包括 v-if , v-show 和 v-repeat。同時&#xff0c;vm 實例的 $appendTo() , $before() , $after() 和 $remove() 方法…

VS擴展工具

原文發布時間為&#xff1a;2011-03-09 —— 來源于本人的百度文章 [由搬家工具導入]http://visualstudiogallery.msdn.microsoft.com/site/search?f%5B0%5D.TypeRootCategory&f%5B0%5D.Valuetools轉載于:https://www.cnblogs.com/handboy/p/7163982.html

工業相機5A參數及其對圖像采集的影響

有些相機會提到5A功能&#xff0c;指的是: Automatic Shutter(自動快門)、Automatic Gain&#xff08;自動增益&#xff09;、Automatic IRIS&#xff08;自動光圈&#xff09;、Automatic Gamma&#xff08;自動伽馬&#xff09;、Automatic White Balance&#xff08;自動白平…

DM6446 OSD

DM6446 OSD TMS320DM6446支持背景窗顏色&#xff0c;兩個視頻窗口&#xff0c;兩個OSD窗口&#xff0c;一個指針(cursor)窗口。它們以遞增的順序排列&#xff1a;一個特有的第二個OSD窗口&#xff08;OSDWIN1&#xff09;可以用來配置成屬性窗口來控制視頻窗口和第一個OSD窗口&…

DOS的一些常用命令

原文發布時間為&#xff1a;2011-02-12 —— 來源于本人的百度文章 [由搬家工具導入]DOS遠程桌面連接命令 mstsc /v: 192.168.1.250 /consolecmd 運行 command刪除文件 rd 文件名/S創建文件 MD 文件名 1. net user admin godmour /add 新建一個…

機器視覺工業鏡頭-Computar

日本Computar鏡頭&#xff0c;全球工業鏡頭、CCTV鏡頭市場占有率第一。CBC板式會社成立于1925年&#xff0c;總部在日本東京。1960年 CBC香港公司成立&#xff0c;是computar鏡頭走向國際市場的前奏。 1979年 研制出第一只手動變焦鏡頭。 1985年 研制出第一款非球面高速鏡頭。1…

C++編程經驗總結1

面向對象的精髓&#xff1a; 主函數其實就是對于類的元素和動作的重新組合來進行一項活動。 一個思想概念&#xff1a;程設是清楚的&#xff0c;完美的。 數學是清楚的&#xff0c;是完美的。 物理是有趣的&#xff0c;尤其是量子物理 生物是清楚的&#xff0c;尤其是基因 外語…

DM365的BSP源碼分析-基于2.6.18內核

DM365的BSP主要包含mach-davinci和plat-davinci兩個目錄&#xff08;及相關頭文件&#xff09;&#xff0c;BSP復雜龐大又極其重要&#xff0c;它主要完成了板級的初始化&#xff0c;比如內存映射&#xff0c;時鐘和電源初始化&#xff0c;中斷和IO初始化&#xff0c;CPU及各模…

第四章:Django 模型 —— 設計系統表

1. Django框架提供了完善的模型&#xff08;Model &#xff09;層來創建和存儲數據&#xff0c;每一個模型對應數據庫中的唯一的一張表。 2. Django 模型基礎知識&#xff1a; 。每一本模型是一個Python類&#xff0c;繼承了django.db.models.Model類 。該模型中每一個屬性一個…

DM365 使用BT656協議驅動LCD的實現

前兩天已經調好了&#xff0c;主要是對davinci_platform.c的修改 因為輸入輸出都為pal的制式&#xff0c;所以就在pal的函數中進行了修改。 在PAL設置的函數中&#xff0c;修改如下&#xff1a; /* * setting PAL mode */ static void davinci_enc_set_pal(struct vid_enc_mode…

工業視覺鏡頭NAVITAR

品牌介紹 美國NAVITAR是優越的上等光學系統制造商和供應商&#xff0c;工業視覺鏡頭NAVITAR為機器視覺、檢測和生物醫學診斷行業提供的定制光學解決方案。 工業視覺鏡頭NAVITAR用于鑒定產品、檢查產品缺陷、測量零件尺寸、操縱機器人設備和協助進行科學分析與探索。 還用來引導…

TCP系列48—擁塞控制—11、FRTO擁塞撤銷

一、概述FRTO虛假超時重傳檢測我們之前重傳章節的文章已經介紹過了&#xff0c;這里不再重復介紹&#xff0c;針對后面的示例在說明兩點1、FRTO只能用于虛假超時重傳的探測&#xff0c;不能用于虛假快速重傳的探測。2、延遲ER重傳觸發的進入Recovery狀態時候&#xff0c;并不會…

娛樂一下

6年前&#xff0c;沒幾個人知道尤里米爾納&#xff08;Yuri Milner&#xff09;是誰。但今天&#xff0c;他已經是地球上最有名的投資人了。 短短幾年內&#xff0c;這家伙掌管的風險投資基金DST&#xff08;數字天空科技&#xff09;投遍了全球的互聯網明星企業&#xff0c;并…

機器視覺行業市場現狀及發展前景分析

1.中國的機器視覺起步較晚&#xff0c;目前正處于快速增長期。 我國機器視覺最早起源于20世紀80年代。機器視覺生產線和先進設備自1998年眾多電子、半導體企業落戶廣東、上海以來&#xff0c;先后在國內誕生了國際代理商和機器視覺系統集成商。 第一個階段是1999-2003年的啟蒙…

從bootm 命令講起/U-boot的環境變量: bootcmd 和bootargs

從bootm 命令講起 1 找到linux的內核入口 Bootm命令通過讀取uImage的頭部040字節的信息&#xff0c;將uImage定位到正確的地址&#xff0c;同時找到linux的內核入口地址。 這個地方就涉及到uImage的頭部040字節信息到底是什么的問題?uboot提供了mkimage命令去把040字節加在lin…