日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JQ对象到底是什么

發布時間:2023/12/13 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

總結

以上是生活随笔為你收集整理的JQ对象到底是什么的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。