最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

jQuery源碼分析之init的詳細介紹

 更新時間:2017年02月13日 10:18:56   作者:漁人  
在閱讀本文之前,相信大家對 jQuery 的總體架構已經(jīng)了解了,這一篇文章主要來介紹 jQuery 的入口函數(shù) jQuery.fn.init。有需要的朋友可以參考借鑒,下面來一起看看吧。

init 構造器

由于這個函數(shù)直接和 jQuery() 的參數(shù)有關,先來說下能接受什么樣的參數(shù)。

源碼中接受 3 個參數(shù):

init: function (selector, context, root) {
 ...
}
  1. jQuery() ,空參數(shù),這個會直接返回一個空的 jQuery 對象,return this。
  2. jQuery( selector [, context ] ) ,這是一個標準且常用法,selector 表示一個 css 選擇器,這個選擇器通常是一個字符串,#id 或者 .class 等,context 表示選擇范圍,即限定作用,可為 DOM,jQuery 對象。
  3. jQuery( element|elements ) ,用于將一個 DOM 對象或 DOM 數(shù)組封裝成 jQuery 對象。
  4. jQuery( jQuery object|object ) ,會把普通的對象或 jQuery 對象包裝在 jQuery 對象中。
  5. jQuery( html [, ownerDocument ] ) ,這個方法用于將 html 字符串先轉成 DOM 對象后在生成 jQuery 對象。
  6. jQuery( html, attributes ) ,和上一個方法一樣,不過會將 attributes 中的方法和屬性綁定到生成的 html DOM 中,比如 class 等。
  7. jQuery( callback ) ,此方法接受一個回掉函數(shù),相當于 window.onload 方法,只是相對于。

介紹完入口,就開始來看源碼。

init: function (selector, context, root) {
 var match, elem;

 // 處理: $(""), $(null), $(undefined), $(false)
 if (!selector) {
 return this;
 }
 // rootjQuery = jQuery( document );
 root = root || rootjQuery;

 // 處理 HTML 字符串情況,包括 $("<div>")、$("#id")、$(".class")
 if (typeof selector === "string") {

 //此部分拆分,留在后面講

 // HANDLE: $(DOMElement)
 } else if (selector.nodeType) {
 this[0] = selector;
 this.length = 1;
 return this;

 // HANDLE: $(function)
 } else if (jQuery.isFunction(selector)) {
 return root.ready !== undefined ? root.ready(selector) :

 // Execute immediately if ready is not present
 selector(jQuery);
 }

 return jQuery.makeArray(selector, this);
}

上面有幾點需要注意,root = root || rootjQuery; ,這個參數(shù)在前面介紹用法的時候,就沒有提及,這個表示 document,默認的話是 rootjQuery,而 rootjQuery = jQuery( document ) 。

可以看出,對于處理 $(DOMElement) ,直接是把 jQuery 當作一個數(shù)組,this[0] = DOMElement 。其實,這要從 jQuery 的基本構造講起,我們完成一個 $('div.span') 之后,然后一個 jQuery 對象(this),其中會得到一組(一個)DOM 對象,jQuery 會把這組 DOM 對象當作數(shù)組元素添加過來,并給一個 length。后面就像一些鏈式函數(shù)操作的時候,若只能對一個 DOM 操作,比如 width、height,就只對第一個元素操作,若可以對多個 DOM 操作,則會對所有 DOM 進行操作,比如 css()。

jQuery 大題思路如下,這是一個非常簡單點實現(xiàn):

jQuery.prototype = {
 // 簡單點,假設此時 selector 用 querySelectorAll
 init: function(selector){
 var ele = document.querySelectorAll(selector);
 // 把 this 當作數(shù)組,每一項都是 DOM 對象
 for(var i = 0; i < ele.length; i++){
 this[i] = ele[i];
 }
 this.length = ele.length;
 return this;
 },
 //css 若只有一個對象,則取其第一個 DOM 對象
 //若 css 有兩個參數(shù),則對每一個 DOM 對象都設置 css
 css : function(attr,val){
 for(var i = 0; i < this.length; i++){
 if(val == undefined){
 if(typeof attr === 'object'){
 for(var key in attr){
 this.css(key, attr[key]);
 }
 }else if(typeof attr === 'string'){
 return getComputedStyle(this[i])[attr];
 }
 }else{
 this[i].style[attr] = val;
 }
 }
 },
}

所以對于 DOMElement 的處理,直接將 DOM 賦值給數(shù)組后,return this。

jQuery.makeArray 是一個綁定 數(shù)組的函數(shù),和上面的原理一樣,后面會談到。

在介紹下面的內(nèi)容之前,先來介紹一個 jQuery 中一個識別 Html 字符串的正則表達式,

var rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;
rquickExpr.exec('<div>') //["<div>", "<div>", undefined]
rquickExpr.exec('<div></div>') //["<div></div>", "<div></div>", undefined]
rquickExpr.exec('#id') //["#id", undefined, "id"]
rquickExpr.exec('.class') //null

上面這一系列的正則表達式 exec,只是為了說明 rquickExpr 這個正則表達式執(zhí)行后的結果,首先,如果匹配到,結果數(shù)組的長度是 3,如果匹配到 <div> 這種 html,數(shù)組的第三個元素是 underfined,如果匹配到 #id,數(shù)組的第二個元素是 underfined,如果匹配不到,則為 null。

另外還有一個正則表達式:

var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
rsingleTag.test('<div></div>') //true
rsingleTag.test('<div ></div>') //true
rsingleTag.test('<div class="cl"></div>') //false
rsingleTag.test('<div></ddiv>') //false

這個正則表達式主要是對 html 的字符串進行驗證,達到不出差錯的效果。在這里不多介紹 exec 和正則表達式了。

下面來看下重點的處理 HTMl 字符串的情況:

if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
 // 這個其實是強行構造了匹配 html 的情況的數(shù)組
 match = [null, selector, null];

} else {
 match = rquickExpr.exec(selector);
}

// macth[1] 限定了 html,!context 對 #id 處理
if (match && (match[1] || !context)) {

 // HANDLE: $(html) -> $(array)
 if (match[1]) {
 //排除 context 是 jQuery 對象情況
 context = context instanceof jQuery ? context[0] : context;

 // jQuery.merge 是專門針對 jQuery 合并數(shù)組的方法
 // jQuery.parseHTML 是針對 html 字符串轉換成 DOM 對象
 jQuery.merge(this, jQuery.parseHTML(
 match[1], context && context.nodeType ? context.ownerDocument || context : document, true));

 // HANDLE: $(html, props)
 if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
 for (match in context) {

 // 此時的 match 非彼時的 match
 if (jQuery.isFunction(this[match])) {
 this[match](context[match]);

 // ...and otherwise set as attributes
 } else {
 this.attr(match, context[match]);
 }
 }
 }

 return this;

 // 處理 match(1) 為 underfined 但 !context 的情況
 } else {
 elem = document.getElementById(match[2]);

 if (elem) {

 // this[0] 返回一個標準的 jQuery 對象
 this[0] = elem;
 this.length = 1;
 }
 return this;
}
// 處理一般的情況,find 實際上上 Sizzle,jQuery 已經(jīng)將其包括進來,下章詳細介紹
// jQuery.find() 為 jQuery 的選擇器,性能良好
} else if (!context || context.jquery) {
 return (context || root).find(selector);
// 處理 !context 情況
} else {
 // 這里 constructor 其實是 指向 jQuery 的
 return this.constructor(context).find(selector);
}

關于 nodeType,這是 DOM 的一個屬性,詳情 Node.nodeType MDN。nodeType 的值一般是一個數(shù)字,比如 1 表示 DOM,3 表示文字等,也可以用這個值是否存在來判斷 DOM 元素,比如 context.nodeType。

整個 init 函數(shù)等構造邏輯,非常清晰,比如 (selector, context, root) 三個參數(shù),分別表示選擇的內(nèi)容,可能存在的的限制對象或 Object,而 root 則默認的 jQuery(document) 。依舊采用 jQuery 常用的方式,對每一個變量的處理都非常的謹慎。

如果仔細看上面兩部分源代碼,我自己也加了注釋,應該可以把整個過程給弄懂。

find 函數(shù)實際上是 Sizzle,已經(jīng)單獨出來一個項目,被在 jQuery 中直接使用,將在下章介紹 jQuery 中的 Sizzle 選擇器。通過源碼,可以發(fā)現(xiàn):

jQuery.find = function Sizzle(){...}
jQuery.fn.find = function(selector){
 ...
 //引用 jQuery.find
 jQuery.find()
 ...
}

衍生的函數(shù)

init 函數(shù)仍然調(diào)用了不少 jQuery 或 jQuery.fn 的函數(shù),下面來逐個分析。

jQuery.merge

這個函數(shù)通過名字,就知道它是用來干什么的,合并。

jQuery.merge = function (first, second) {
 var len = +second.length,
 j = 0,
 i = first.length;

 for (; j < len; j++) {
 first[i++] = second[j];
 }

 first.length = i;

 return first;
}

這樣子就可以對類似于數(shù)組且有 length 參數(shù)的類型進行合并,我感覺主要還是為了方便對 jQuery 對象的合并,因為 jQuery 對象就是有 length 的。

jQuery.parseHTML

這個函數(shù)也非常有意思,就是將一串 HTML 字符串轉成 DOM 對象。

首先函數(shù)接受三個參數(shù),第一個參數(shù) data 即為 html 字符串,第二個參數(shù)是 document 對象,但要考慮到瀏覽器的兼容性,第三個參數(shù) keepScripts 是為了刪除節(jié)點里所有的 script tags,但在 parseHTML 里面沒有體現(xiàn),主要還是給 buildFragment 當作參數(shù)。

總之返回的對象,是一個 DOM 數(shù)組或空數(shù)組。

jQuery.parseHTML = function (data, context, keepScripts) {
 if (typeof data !== "string") {
 return [];
 }
 // 平移參數(shù)
 if (typeof context === "boolean") {
 keepScripts = context;
 context = false;
 }

 var base, parsed, scripts;

 if (!context) {

 // 下面這段話的意思就是在 context 缺失的情況下,建立一個 document 對象
 if (support.createHTMLDocument) {
 context = document.implementation.createHTMLDocument("");
 base = context.createElement("base");
 base.href = document.location.href;
 context.head.appendChild(base);
 } else {
 context = document;
 }
 }
 // 用來解析 parsed,比如對 "<div></div>" 的處理結果 parsed:["<div></div>", "div"]
 // parsed[1] = "div"
 parsed = rsingleTag.exec(data);
 scripts = !keepScripts && [];

 // Single tag
 if (parsed) {
 return [context.createElement(parsed[1])];
 }
 // 見下方解釋
 parsed = buildFragment([data], context, scripts);

 if (scripts && scripts.length) {
 jQuery(scripts).remove();
 }

 return jQuery.merge([], parsed.childNodes);
}

buildFragment 函數(shù)主要是用來建立一個包含子節(jié)點的 fragment 對象,用于頻發(fā)操作的添加刪除節(jié)點。parsed = buildFragment([data], context, scripts);建立好一個 fragment 對象,用 parsed.childNodes 來獲取這些 data 對應的 HTML。

jQueyr.makeArray

jQuery 里面的函數(shù)調(diào)用,真的是一層接一層,雖然有時候光靠函數(shù)名,就能知道這函數(shù)的作用,但其中思考之邏輯還是挺參考意義的。

jQuery.makeArray = function (arr, results) {
 var ret = results || [];

 if (arr != null) {
 if (isArrayLike(Object(arr))) {
 jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
 } else {
 push.call(ret, arr);
 }
 }

 return ret;
}

makeArray 把左邊的數(shù)組或字符串并入到右邊的數(shù)組或一個新數(shù)組,其中又間接的引用 jQuery.merge 函數(shù)。

接下來是著 isArrayLike 函數(shù),可能需要考慮多方面的因素,比如兼容瀏覽器等,就有了下面這一長串:

function isArrayLike(obj) {

 // Support: real iOS 8.2 only (not reproducible in simulator)
 // `in` check used to prevent JIT error (gh-2145)
 // hasOwn isn't used here due to false negatives
 // regarding Nodelist length in IE
 var length = !!obj && "length" in obj && obj.length,
 type = jQuery.type(obj);

 if (type === "function" || jQuery.isWindow(obj)) {
 return false;
 }

 return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj;
}

總結

這篇文章主要介紹了jQuery中比較重要的入口函數(shù),之后將會繼續(xù)講解 Sizzle,jQuery 中的選擇器。感興趣的朋友們請繼續(xù)關注腳本之家,謝謝大家的支持。

相關文章

  • addEventListener—jQuery的事件監(jiān)聽方法

    addEventListener—jQuery的事件監(jiān)聽方法

    在Javascript中,事件監(jiān)聽是非常重要的,通過事件監(jiān)聽,我們可以在用戶執(zhí)行某些操作時觸發(fā)相應的處理程序。最初,Javascript監(jiān)聽事件的方式是addEvent。addEvent()比較麻煩,所以jQuery為我們提供了一個更為便捷的事件監(jiān)聽方法:addEventListener。
    2023-06-06
  • jquery 事件執(zhí)行檢測代碼

    jquery 事件執(zhí)行檢測代碼

    在寫Web 應用,或者Web Ajax功能的時候我們經(jīng)常需要處理事件,jquery已經(jīng)非常完美的封裝了事件,但是有時候事件的執(zhí)行順序還是會有微小差別
    2009-12-12
  • JQuery表單驗證插件EasyValidator用法分析

    JQuery表單驗證插件EasyValidator用法分析

    這篇文章主要介紹了JQuery表單驗證插件EasyValidator用法,以實例形式系統(tǒng)分析了EasyValidator的功能特性及具體用法,是非常實用的jQuery插件,需要的朋友可以參考下
    2014-11-11
  • jQuery中:radio選擇器用法實例

    jQuery中:radio選擇器用法實例

    這篇文章主要介紹了jQuery中:radio選擇器用法,實例分析了:radio選擇器的功能、定義及匹配單選按鈕的使用技巧,需要的朋友可以參考下
    2015-01-01
  • 利用jquery去掉時光軸頭尾部線條的方法實例

    利用jquery去掉時光軸頭尾部線條的方法實例

    這篇文章主要給大家介紹了利用jquery實現(xiàn)去掉時光軸頭尾部線條的方法,文中給出了詳細的實例代碼供大家參考學習,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • jQuery驗證表單格式的使用方法

    jQuery驗證表單格式的使用方法

    本文給大家講解關于此jQuery驗證的一些標記以及使用方法,非常不錯,具有參考借鑒借鑒價值,需要的朋友參考下
    2017-01-01
  • EasyUI中的tree用法介紹

    EasyUI中的tree用法介紹

    不知不覺10月都結束了,又要到年底了??纯醋约荷洗螌戇^的文章后,已經(jīng)2個月都沒寫東西了
    2011-11-11
  • 關于jQuery判斷元素是否存在的問題示例探討

    關于jQuery判斷元素是否存在的問題示例探討

    這篇文章主要探討了關于jQuery判斷元素是否存在的問題,需要的朋友可以參考下
    2014-07-07
  • Jquery中getJSON在asp.net中的使用說明

    Jquery中getJSON在asp.net中的使用說明

    Jquery中getJSON在asp.net中的使用說明,需要的朋友可以參考下。
    2011-03-03
  • 用jQuery解決IE不支持的option disable屬性

    用jQuery解決IE不支持的option disable屬性

    使用jQuery解決IE不支持的option disable屬性
    2009-05-05

最新評論

民丰县| 突泉县| 建始县| 普陀区| 吉安市| 长春市| 大理市| 富平县| 石嘴山市| 石楼县| 太仓市| 台州市| 东兰县| 镇沅| 四子王旗| 山西省| 灌云县| 静乐县| 沙雅县| 巫山县| 定州市| 滦南县| 稷山县| 永靖县| 根河市| 仁化县| 兴宁市| 宝丰县| 武陟县| 车险| 仲巴县| 登封市| 扎兰屯市| 韩城市| 邹城市| 富川| 顺昌县| 大石桥市| 咸阳市| 博爱县| 田东县|