在构造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; }