在構造jQuery對象模塊中還定義了一些重要的靜態屬性和方法,它們時其餘模塊實現的基礎。html
// 涉及外部代碼行 // 代碼行:48——124 var arr = []; var document = window.document; // 該方法與 setPrototypeOf 方法配套,用於讀取一個對象的 prototype 對象。 var getProto = Object.getPrototypeOf; var slice = arr.slice; var concat = arr.concat; var push = arr.push; var indexOf = arr.indexOf; var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var fnToString = hasOwn.toString; var ObjectFunctionString = fnToString.call( Object ); var support = {}; // isFunction(obj)用於判斷傳入的參數是不是函數 var isFunction = function isFunction(obj) { // Support: Chrome <=57, Firefox <=52 // In some browsers, typeof returns "function" for HTML <object> elements // (i.e., `typeof document.createElement( "object" ) === "function"`). // We don't want to classify *any* DOM node as a function. // nodeType 屬性可返回節點的類型。 /* nodeType值-元素類型 1-ELEMENT 2-ATTRIBUTE 3-TEXT 4-CDATA 5-ENTITY REFERENCE 6-ENTITY 7-PI (processing instruction) 8-COMMENT 9-DOCUMENT 10-DOCUMENT TYPE 11-DOCUMENT FRAGMENT 12-NOTATION */ return typeof obj === "function" && typeof obj.nodeType !== "number"; }; // isWindow(obj)用於判斷傳入的參數是不是window對象,經過檢測是否存在特徵屬性window來實現。 var isWindow = function isWindow(obj) { return obj != null && obj === obj.window; }; // 變量用於保存腳本屬性 var preservedScriptAttributes = { type: true, src: true, noModule: true }; // 使用 jQuery html() 方法時插入的腳本老是執行的,jQuery 會檢查傳入的內容,並執行其中的每個腳本。 function DOMEval(code, doc, node) { doc = doc || document; // 設置當前文檔,默認爲document var i, script = doc.createElement("script"); // 在文檔中添加script節點 script.text = code; // 給script添加內容 // 若是存在節點 if (node) { for (i in preservedScriptAttributes) { if (node[i]) { script[i] = node[i]; } } } doc.head.appendChild(script).parentNode.removeChild(script); // 將代碼放入文檔中,當即執行,而後當即刪除; } // 方法toType(obj)用於判斷參數的內建JavaScript類型。 function toType(obj) { // 若是參數是undefined或null,返回"undefined"或"null "; if (obj == null) { return obj + ""; } // Support: Android <=2.3 only (functionish RegExp) // 若是參數是JavaScript內部對象,則返回對應的字符串名稱;其餘狀況一概返回"object"或"function"或class2type的類型。 return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj; } // 代碼行:144 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; // 主代碼行:296——498 jQuery.extend({ // Unique for each copy of jQuery on the page // 經過隨機數(Math.random())給每一個副本都設定一個惟一值,而且經過正則replace( /\D/g, "" )把全部非數字替換成空。\D相似於[^0-9] 非數字。 expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""), // Assume jQuery is ready without the ready module // 設定jQuery在模塊未加載的狀況依然加載完畢。 isReady: true, // error(msg),接受一個字符串,拋出一個包含了該字符串的異常。開發插件時能夠覆蓋這個方法,用來顯示更有用或更多的錯誤提示消息。 error: function (msg) { throw new Error(msg); }, // noop()表示一個空函數。當但願傳遞一個什麼也不作的函數時,能夠使用空函數。開發插件時,這個方法能夠作爲可選回調函數的默認值,若是沒有提供回調函數,則執行jQuery.noop()。 noop: function () {}, // isPlainObject(object)用於判斷傳入的參數是不是「純粹的對象」,便是否是用對象直接量{}或new Object()建立的對象。 isPlainObject: function (obj) { var proto, Ctor; // Detect obvious negatives // Use toString instead of jQuery.type to catch host objects // 若是參數obj知足如下條件之一,則返回false: // 參數obj能夠轉換爲false // Object.prototype.toString.call(obj)返回的不是[object Object] // 若是不知足以上全部條件,則至少能夠肯定參數obj是對象。 if (!obj || toString.call(obj) !== "[object Object]") { return false; } // 讀取obj對象的 prototype 對象並賦值給proto proto = getProto(obj); // Objects with no prototype (e.g., `Object.create( null )`) are plain // 若是對象是個普通的對象沒有原型(例如,Object.create(null))則返回true。 if (!proto) { return true; } // Objects with prototype are plain iff they were constructed by a global Object function // 函數hasOwn.call()指向Object.prototype.hasOwnProperty(property),用於檢測對象是否含有執行名稱的非繼承性。 // fnToString:將函數轉換成字符串 ObjectFunctionString:function Object() { [native code] } Ctor = hasOwn.call(proto, "constructor") && proto.constructor; // 返回判斷對象是否是經過newObject()方式建立的結果 return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; }, // isEmptyObject(object)用於檢測對象是否爲空(即不包含屬性) isEmptyObject: function (obj) { /* eslint-disable no-unused-vars */ // See https://github.com/eslint/eslint/issues/6125 var name; // for-in循環會同時枚舉非繼承屬性和從原型對象繼承的屬性,若是有,則當即返回false,不然默認返回true。 for (name in obj) { return false; } return true; }, // Evaluates a script in a global context // jQuery.globalEval(code):用於在全局做用域中執行JavaScript代碼。 globalEval: function (code) { // code:待執行的JavaScript語句或表達式 DOMEval(code); }, // 靜態方法jQuery.each()是一個通用的遍歷迭代方法,用於無縫地遍歷對象和數組。對於數組和含有length屬性的類數組對象。改方法經過下標遍歷,從0到length-1;對於其餘對象則經過屬性名遍歷(for-in),在遍歷過程當中,若是回調函數返回false,則結束遍歷。 each: function (obj, callback) { // obj:待遍歷的數組或對象。 // callback:回調函數,會在數組的每一個元素或對象的每一個屬性上執行。 var length, i = 0; // 對於數組或類數組對象,經過for循環遍歷下標。 if (isArrayLike(obj)) { length = obj.length; for (; i < length; i++) { // 執行回調函數時傳入3個參數:元素、下標、元素 if (callback.call(obj[i], i, obj[i]) === false) { break; } } // 對於對象用for-in循環遍歷屬性名。 } else { for (i in obj) { // 執行回調函數時傳入連個參數:對應的屬性值、下標或屬性名、對應的屬性值。 if (callback.call(obj[i], i, obj[i]) === false) { break; } } } // 返回obj return obj; }, // Support: Android <=4.0 only // jQuery.trim(text):用於移除字符串開頭和結尾的空白符。若是是null返回空字符串,不然將text轉成字符串,經過replace()中正則表達式rtrim匹配的子串並返回。 trim: function (text) { return text == null ? "" : (text + "").replace(rtrim, ""); }, // results is for internal usage only // makeArray能夠將一個類數組轉換成真正的數組。若是傳入第二個參數resullts(僅在jQuery內部使用),第一個參數arr中的元素將被合併入第二個參數,最後返回第二個參數,此時返回的不必定是真正的數組。 makeArray: function (arr, results) { // arr:待轉換對象,能夠是任何類型 // results:僅在jQuery內部使用。若是傳入參數resultes,則在該參數上添加元素。 // 定義返回值ret。若是傳入了參數result則把該參數做爲返回值,不然新建一個空數組做爲返回值。 var ret = results || []; // 若是傳入的參數arr不是null、undefined的狀況 if (arr != null) { // 使用isArrayLike判斷arr是不是數組或類數組對象。若是是數組或類數組對象,調用jQuery.merge()將arr合併到返回值ret中 if (isArrayLike(Object(arr))) { jQuery.merge(ret, typeof arr === "string" ? [arr] : arr ); // 不然,由於不肯定ret的格式。因此選擇push.call()的方式合併而不是ret.push()。若是隻傳入參數array,則返回值ret是真正的數組;若是還傳入了第二個參數result,則返回值ret的類型取決於該參數的類型。 } else { push.call(ret, arr); } } // 返回ret return ret; }, // 在數組中查找指定的下標並返回其下標。elem要查找的值,arr將遍歷的數組,i指定查找的位置。 inArray: function (elem, arr, i) { // elem:要查找的值 // arr:數組,將遍歷這個數組來查找參數value在其中的下標 // i:指定開始查找的位置 // 若是數組爲空,則默認返回-1。不然調用indexOf.call()方法返回其下標 return arr == null ? -1 : indexOf.call(arr, elem, i); }, // Support: Android <=4.0 only, PhantomJS 1 only // push.apply(_, arraylike) throws on ancient WebKit // 用於合併兩個數組的元素到第一個數組中,第一個參數能夠是數組或類數組對象,即必須含有整數(或能夠轉換成整些)屬性length;第二個參數能夠數組,類數組對象或任何含有連續屬性的對象。注意:方法jQuery.merge()的合併具備破壞性,將第二個參數合併到第一個參數時,會改變第一個參數。若是不但願改變第一個參數,能夠在調用jQuery.merge()方法前對第一個參數進行備份。 merge: function (first, second) { // 初始化變量,將second.length轉換成數字,並將first.length賦值給i,循環添加second的屬性到first中,由於不肯定first是不是數組,因此用i來修正first.length。最後返回first。 var len = +second.length, j = 0, i = first.length; for (; j < len; j++) { first[i++] = second[j]; } first.length = i; return first; }, // 用於查找數組中知足過濾函數的元素,原數組不受影響。 grep: function (elems, callback, invert) { // elems待遍歷查找的數組 // callback過濾每一個元素的函數,執行時被傳入兩個參數;當前元素和它的下標。該函數應該返回一個布爾值。 // invert若是參數是false或未傳入,grep()會返回一個知足回調函數的元素數組;若是invert是true,則返回一個不知足回調函數的元素數組。 var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // Go through the array, only saving the items // that pass the validator function // 遍歷數組elems,爲每一個元素執行過濾函數。若是參數invert爲true,把執行結果爲false的元素放入結果數組matches;若是參數invert爲false,把執行結果爲true的元素放入結果數組matches; for (; i < length; i++) { callbackInverse = !callback(elems[i], i); if (callbackInverse !== callbackExpect) { matches.push(elems[i]); } } // 返回結果數組matches return matches; }, // arg is for internal usage only // 靜態方法jQuery.map()對數組中的每一個元素或對象的每一個屬性調用一個回調函數,並將回調函數的返回值放入一個新數組中。執行回調函數時傳入兩個參數:數組元素或屬性值,元素下標或屬性名。關鍵字this指向全局對象window。回調函數的返回值會被放入新的數組中;若是返回一個數組,數組中將被扁平化後插入結果集;若是返回null或undefined,則不會放入任何元素。 map: function (elems, callback, arg) { // elems:待遍歷的數組或對象 // callback:回調函數,會在數組的每一個元素或對象的每一個屬性上執行。執行時傳入兩個參數:數組元素或屬性值,元素下標或屬性名。 // arg:僅限於jQuery內部使用。若是調用jQuery.map()時傳入了參數arg,則該參數會被傳給回調函數callback。 var length, value, i = 0, ret = []; // Go through the array, translating each of the items to their new values // 判斷elems是數組,若是爲true,將經過下標遍歷 if (isArrayLike(elems)) { length = elems.length; for (; i < length; i++) { // 爲每一個元素執行回調函數callback,執行時依次傳入三個參數:元素、下標、arg value = callback(elems[i], i, arg); // 若是回調函數的返回值不是null和undefined,則把返回值放入結果集ret if (value != null) { ret.push(value); } } // Go through every key on the object, // 不然將經過屬性名遍歷 } else { // 對於對象經過for..in循環遍歷屬性名 for (i in elems) { // 爲每一個屬性值執行回調函數callback,執行時依次傳入三個參數:元素、下標、arg value = callback(elems[i], i, arg); // 若是回調函數的返回值不是null和undefined,則把返回值放入結果集ret if (value != null) { ret.push(value); } } } // Flatten any nested arrays // 最後在空數組[]上調用方法concat()扁平化結果集ret中的元素,並返回。 return concat.apply([], ret); }, // A global GUID counter for objects // guid是一個全局計數器,用於jQuery事件模塊和緩存模塊。在jQuery事件模塊中,每一個事件監聽函數會被設置一個guid屬性,用來惟一標識這個函數。在緩存模塊中,經過在DOM元素上附加一個惟一標識,來關聯元素和該元素對應的緩存。屬性jQuery.guid初始值爲1,使用時自增1。 guid: 1, // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. // support用於其餘項目附加它們的屬性 support: support }); // 添加Symbol屬性 if (typeof Symbol === "function") { jQuery.fn[Symbol.iterator] = arr[Symbol.iterator]; // 爲 arr與jQuery.fn添加Symbol.iterator屬性 // Symbol.iterator 爲每個對象定義了默認的迭代器。該迭代器能夠被 for...of 循環使用。 } // Populate the class2type map // 初始化class2type結果爲: /* { "[object Boolean]":"boolean", "[object Number]":"number", "[object String]":"string", "[object Function]":"function", "[object Array]":"array", "[object Date]":"date", "[object RegExp]":"regexp", "[object Object]":"object", "[object Error]":"error", "[object Symbol]":"symbol", } */ jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function (i, name) { class2type["[object " + name + "]"] = name.toLowerCase(); }); // 用於判斷obj是數組仍是對象 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 //!!obj 用於判斷obj是非空的,即obj不是undefined、null或""(空)。 var length = !!obj && "length" in obj && obj.length, type = toType(obj); // 是函數或窗口返回false if (isFunction(obj) || isWindow(obj)) { return false; } // elem.length是數值型,知足下列條件則爲true;obj是真正的數組、length等於0、length大於0,且length - 1存在,便是一個類數組對象。 return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj; }