@ -3,7 +3,567 @@
* Includes : widget . js , position . js , data . js , disable - selection . js , effect . js , effects / effect - blind . js , effects / effect - bounce . js , effects / effect - clip . js , effects / effect - drop . js , effects / effect - explode . js , effects / effect - fade . js , effects / effect - fold . js , effects / effect - highlight . js , effects / effect - puff . js , effects / effect - pulsate . js , effects / effect - scale . js , effects / effect - shake . js , effects / effect - size . js , effects / effect - slide . js , effects / effect - transfer . js , focusable . js , form - reset - mixin . js , jquery - 1 - 7. js , keycode . js , labels . js , scroll - parent . js , tabbable . js , unique - id . js , widgets / accordion . js , widgets / autocomplete . js , widgets / button . js , widgets / checkboxradio . js , widgets / controlgroup . js , widgets / datepicker . js , widgets / dialog . js , widgets / draggable . js , widgets / droppable . js , widgets / menu . js , widgets / mouse . js , widgets / progressbar . js , widgets / resizable . js , widgets / selectable . js , widgets / selectmenu . js , widgets / slider . js , widgets / sortable . js , widgets / spinner . js , widgets / tabs . js , widgets / tooltip . js
* Copyright jQuery Foundation and other contributors ; Licensed MIT * /
( function ( global , factory ) {
// 如果在CommonJS环境中( 如Node.js) , 并且module.exports存在
if ( typeof module === "object" && typeof module . exports === "object" ) {
// 如果全局对象有document属性, 则直接导出jQuery
// 否则, 导出一个函数, 该函数在被调用时会检查是否存在document
module . exports = global . document ?
factory ( global , true ) :
function ( w ) {
// 如果没有document, 则抛出错误
if ( ! w . document ) {
throw new Error ( "jQuery需要一个包含document的window对象" ) ;
}
// 否则, 调用factory函数创建jQuery
return factory ( w ) ;
} ;
} else {
// 在非CommonJS环境中, 直接调用factory函数
factory ( global ) ;
}
} ( typeof window !== "undefined" ? window : this , function ( window , noGlobal ) {
// 用于存储已删除的ID的数组
var deletedIds = [ ] ;
// 获取全局的document对象
var document = window . document ;
// 从deletedIds数组借用一些数组方法, 用于后续操作
var slice = deletedIds . slice ;
var concat = deletedIds . concat ;
var push = deletedIds . push ;
var indexOf = deletedIds . indexOf ;
// 一个空对象,用于存储类名到类型的映射
var class2type = { } ;
// 获取class2type对象的toString方法
var toString = class2type . toString ;
// 获取class2type对象的hasOwnProperty方法
var hasOwn = class2type . hasOwnProperty ;
// 一个空对象,用于存储浏览器支持的特性
var support = { } ;
// jQuery的版本号
var version = "1.12.4" ;
// 定义jQuery对象, 它实际上是init构造函数的增强版
var jQuery = function ( selector , context ) {
// 如果直接调用jQuery而没有new, 这里会返回一个新的jQuery.fn.init实例
return new jQuery . fn . init ( selector , context ) ;
} ;
// 匹配并去除字符串开头和结尾的空白字符( 包括BOM和NBSP)
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g ;
// 匹配以"-ms-"开头的字符串
var rmsPrefix = /^-ms-/ ;
// 匹配并替换字符串中的"-"后跟一个字母或数字的字符
var rdashAlpha = /-([\da-z])/gi ;
// 用于将"-"后跟字母的字符串转换为驼峰命名法的回调函数
var fcamelCase = function ( all , letter ) {
return letter . toUpperCase ( ) ;
} ;
// jQuery的原型对象, 包含所有实例方法
jQuery . fn = jQuery . prototype = {
// 当前jQuery的版本号
jquery : version ,
// 构造函数指向jQuery本身
constructor : jQuery ,
// 初始选择器字符串
selector : "" ,
// jQuery对象的默认长度为0
length : 0 ,
// 将jQuery对象转换为一个真正的数组
toArray : function ( ) {
return slice . call ( this ) ;
} ,
// 获取jQuery对象中的第N个元素, 或者获取所有元素组成的数组
get : function ( num ) {
return num != null ?
// 返回指定位置的元素
( num < 0 ? this [ num + this . length ] : this [ num ] ) :
// 返回所有元素组成的数组
slice . call ( this ) ;
} ,
// 将一个元素数组推入到当前jQuery对象的栈中, 并返回新的jQuery对象
pushStack : function ( elems ) {
// 创建一个新的jQuery对象
var ret = jQuery . merge ( this . constructor ( ) , elems ) ;
// 将旧的对象引用添加到新对象的prevObject属性上
ret . prevObject = this ;
// 保持上下文的一致性
ret . context = this . context ;
// 返回新的jQuery对象
return ret ;
} ,
// 对jQuery对象中的每个元素执行一次提供的回调函数
each : function ( callback ) {
return jQuery . each ( this , callback ) ;
} ,
// 将jQuery对象中的每个元素通过提供的回调函数映射到一个新数组中, 并返回一个新的jQuery对象
map : function ( callback ) {
return this . pushStack ( jQuery . map ( this , function ( elem , i ) {
return callback . call ( elem , i , elem ) ;
} ) ) ;
} ,
// 返回一个从当前位置开始, 包含指定数量元素的新jQuery对象( 如果参数是负数, 则从末尾开始计数)
slice : function ( ) {
return this . pushStack ( slice . apply ( this , arguments ) ) ;
} ,
// 获取jQuery对象中的第一个元素
first : function ( ) {
return this . eq ( 0 ) ;
} ,
// 获取jQuery对象中的最后一个元素
last : function ( ) {
return this . eq ( - 1 ) ;
} ,
// 获取jQuery对象中指定位置的元素( 如果索引是负数, 则从末尾开始计数)
eq : function ( i ) {
var len = this . length ,
j = + i + ( i < 0 ? len : 0 ) ;
return this . pushStack ( j >= 0 && j < len ? [ this [ j ] ] : [ ] ) ;
} ,
// 结束当前操作, 返回到上一个jQuery对象( 如果有的话)
end : function ( ) {
return this . prevObject || this . constructor ( ) ;
} ,
// 以下方法是从数组对象中借用来的,用于内部使用
push : push ,
sort : deletedIds . sort ,
splice : deletedIds . splice
} ;
// jQuery.extend方法用于扩展jQuery对象本身或其原型对象
jQuery . extend = jQuery . fn . extend = function ( ) {
var src , copyIsArray , copy , name , options , clone ,
target = arguments [ 0 ] || { } ,
i = 1 ,
length = arguments . length ,
deep = false ;
// 处理深度复制的情况
if ( typeof target === "boolean" ) {
deep = target ;
// 跳过布尔值和目标对象
target = arguments [ i ] || { } ;
i ++ ;
}
// 如果目标不是对象或函数,则将其转换为对象
if ( typeof target !== "object" && ! jQuery . isFunction ( target ) ) {
target = { } ;
}
// 如果只有一个参数, 则扩展jQuery本身
if ( i === length ) {
target = this ;
i -- ;
}
// 遍历每一个要扩展的对象
for ( ; i < length ; i ++ ) {
// 只处理非null/undefined的值
if ( ( options = arguments [ i ] ) != null ) {
// 扩展基础对象
for ( name in options ) {
src = target [ name ] ;
copy = options [ name ] ;
// 防止无限循环
if ( target === copy ) {
continue ;
}
// 深度复制的逻辑(略)
// Recurse if we're merging plain objects or arrays
// 定义一个函数,用于扩展对象或合并对象
// deep 参数指示是否进行深度拷贝
// copy 是要合并到第一个对象中的对象或数组
// target 是被扩展的对象
// 定义一个函数,它应该是在`jQuery.extend`相关逻辑中用于处理对象属性合并或赋值的具体操作函数,
// 参数`deep`表示是否进行深度拷贝,`copy`是要合并到目标对象中的对象或值,`target`是目标对象,即要被扩展的对象。
var someFunction = function ( deep , copy , target ) {
// 检查是否需要进行深度拷贝,并且`copy`是一个纯对象(通过`jQuery.isPlainObject`判断)或者是一个数组(通过`jQuery.isArray`判断)。
// 这里的逻辑用于区分不同的数据类型情况,以便后续进行相应的处理,比如深度拷贝数组或对象,或者简单赋值等操作。
if ( deep && copy && ( jQuery . isPlainObject ( copy ) ||
( copyIsArray = jQuery . isArray ( copy ) ) ) ) {
// 如果`copy`是数组
if ( copyIsArray ) {
// 重置`copyIsArray`标志位,因为已经确认是数组的情况了,后续不需要再重复判断,将其设置为`false`。
copyIsArray = false ;
// 根据`src`(应该是目标对象`target`中对应属性原来的值,在外部可能有定义,此处代码未完整显示其赋值情况)是否为数组来决定`clone`的值。
// 如果`src`是数组,就将`clone`赋值为`src`(相当于复用已有的数组引用),否则创建一个新的空数组赋值给`clone`,这一步是为后续可能的深度拷贝数组做准备。
clone = src && jQuery . isArray ( src ) ? src : [ ] ;
} else {
// 如果`copy`不是数组而是纯对象,同样根据`src`是否为纯对象来决定`clone`的值。
// 如果`src`是纯对象,就将`clone`赋值为`src`(复用已有的对象引用),否则创建一个新的空对象赋值给`clone`,为后续对纯对象进行深度拷贝等操作做准备。
clone = src && jQuery . isPlainObject ( src ) ? src : { } ;
}
// 从不直接移动原始对象,而是克隆它们,这里调用`jQuery.extend`方法进行合并操作,根据`deep`参数决定是否进行深度拷贝,
// 将`clone`(已处理好的目标对象对应属性的初始值或者新创建的空对象/空数组)、`copy`(要合并进来的对象或值)进行合并,
// 合并后的结果赋值给目标对象`target`的`name`属性(`name`应该是外部循环遍历属性时的当前属性名,此处代码未完整展示其定义情况)。
target [ name ] = jQuery . extend ( deep , clone , copy ) ;
// 如果不需要深度拷贝,并且`copy`不是`undefined`(即有明确的值要赋值),则直接将`copy`赋值给目标对象`target`的`name`属性。
} else if ( copy !== undefined ) {
target [ name ] = copy ;
}
}
// `jQuery.extend`方法用于扩展`jQuery`对象本身或其原型对象,在这里通过传入一个对象字面量作为参数,相当于给`jQuery`添加了一系列的静态方法(即可以直接通过`jQuery`调用,而不是通过`jQuery`实例调用的方法),这些静态方法提供了各种常用的功能和工具函数。
jQuery . extend ( {
// 每个`jQuery`实例在页面上的唯一标识符,通过将版本号、随机数等组合并去除非数字字符生成一个唯一的字符串,
// 用于在页面中区分不同的`jQuery`实例或者在操作DOM元素等场景下作为标识使用, 确保唯一性和可识别性。
expando : "jQuery" + ( version + Math . random ( ) ) . replace ( /\D/g , "" ) ,
// 假设没有`ready`模块时,标记`jQuery`已准备好的状态,这个属性可以在一些初始化或者判断`jQuery`是否就绪的逻辑中使用,
// 比如在页面加载完成后,根据这个属性来决定是否可以执行后续的`jQuery`相关操作等情况。
isReady : true ,
// 错误处理函数,当遇到错误情况时,它会抛出一个包含指定错误消息的`Error`对象,
// 可以在`jQuery`代码的其他地方调用这个函数来统一处理错误情况,使得错误信息能规范地抛出并被捕获处理,方便调试和错误提示。
error : function ( msg ) {
throw new Error ( msg ) ;
} ,
// 空函数,常用于作为回调函数的占位符,在一些需要传入回调函数但暂时又不需要具体实现功能的场景下使用,
// 比如在初始化一些组件或者设置事件监听器时,可以先传入这个空函数,后续再根据实际需求替换为具体的回调函数实现相应功能。
noop : function ( ) { } ,
// 判断对象是否为函数的方法,通过调用`jQuery.type`方法来判断对象的类型是否为`"function"`,返回布尔值结果,
// 方便在代码中根据对象是否为函数来执行不同的逻辑,例如判断某个参数是否是可执行的函数,然后决定是否调用它等情况。
isFunction : function ( obj ) {
return jQuery . type ( obj ) === "function" ;
} ,
// 判断对象是否为数组的方法,首先尝试使用原生的`Array.isArray`方法(如果浏览器支持的话)来判断,
// 如果浏览器不支持,则通过调用`jQuery.type`方法判断对象的类型是否为`"array"`来确定是否为数组,这样可以在不同浏览器环境下统一判断对象是否为数组,便于处理数组相关的逻辑。
isArray : Array . isArray || function ( obj ) {
return jQuery . type ( obj ) === "array" ;
} ,
// 判断对象是否为窗口对象(通常指浏览器的`window`对象)的方法,通过检查对象是否不为`null`并且该对象本身就是其`window`属性来判断,
// 主要用于在代码中区分是否是浏览器窗口对象, 例如在操作DOM、处理全局变量等场景下, 需要确定某个对象是否是窗口对象来执行不同的逻辑。
isWindow : function ( obj ) {
return obj != null && obj == obj . window ;
} ,
// 判断对象是否为数字的方法,先获取对象的字符串表示形式(通过`toString`方法),然后将其转换为浮点数并与原字符串表示形式转换后的数字进行比较,
// 如果差值加上1大于等于0, 则认为该对象可以被看作是数字类型, 用于在代码中判断传入的参数或者变量是否为数字, 进而进行相应的数值计算或者逻辑处理。
isNumeric : function ( obj ) {
var realStringObj = obj && obj . toString ( ) ;
return ! jQuery . isArray ( obj ) && ( realStringObj - parseFloat ( realStringObj ) + 1 ) >= 0 ;
} ,
// 判断对象是否为空对象(即没有自身属性的对象)的方法,通过遍历对象的属性,只要能找到一个属性就返回`false`,表示不是空对象,
// 如果遍历完所有属性都没有找到,则返回`true`,表示对象是空对象,常用于在处理对象数据时,判断是否需要进行某些初始化或者特殊处理等情况。
isEmptyObject : function ( obj ) {
var name ;
for ( name in obj ) {
return false ;
}
return true ;
} ,
// 判断对象是否为纯对象(即直接通过`{}`或`new Object()`创建的对象,不包括通过构造函数等方式创建的具有特定原型链的对象)的方法,
// 通过一系列的条件判断,如对象是否存在、类型是否为`"object"`、是否是节点对象、是否是窗口对象等情况进行排除,
// 还会通过一些原型相关的属性检查以及异常处理等来综合判断对象是否为纯对象,用于在处理对象合并、拷贝等操作中准确区分对象类型,决定相应的处理方式。
isPlainObject : function ( obj ) {
var key ;
if ( ! obj || jQuery . type ( obj ) !== "object" || obj . nodeType || jQuery . isWindow ( obj ) ) {
return false ;
}
try {
if ( obj . constructor &&
! hasOwn . call ( obj , "constructor" ) &&
! hasOwn . call ( obj . constructor . prototype , "isPrototypeOf" ) ) {
return false ;
}
} catch ( e ) {
return false ;
}
if ( ! support . ownFirst ) {
for ( key in obj ) {
return hasOwn . call ( obj , key ) ;
}
}
for ( key in obj ) { }
return key === undefined || hasOwn . call ( obj , key ) ;
} ,
// 获取对象的类型的方法,首先判断对象是否为`null`,如果是则直接返回其字符串表示形式(通常是`"null"`) ,
// 如果对象不为`null`,则进一步判断如果对象是对象类型或者函数类型,通过`class2type`对象(应该是之前定义用于类型映射的对象)结合`toString`方法来获取更准确的类型名称(如果`class2type`中有对应映射则返回映射的名称,否则返回`"object"`) ,
// 如果不是对象或函数类型,则直接返回对象的`typeof`操作得到的基本类型名称,用于在代码中准确获取对象的类型信息,方便进行类型相关的判断和处理逻辑。
type : function ( obj ) {
if ( obj == null ) {
return obj + "" ;
}
return typeof obj === "object" || typeof obj === "function" ?
class2type [ toString . call ( obj ) ] || "object" :
typeof obj ;
} ,
// 在全局上下文中执行JavaScript代码的方法, 首先检查传入的代码字符串`data`是否存在并且去除两端空白字符后不为空,
// 如果满足条件,则尝试使用`window.execScript`(某些浏览器支持的执行脚本的方法)来执行代码,如果浏览器不支持`execScript`,
// 则通过`window["eval"]`( `eval`函数可以执行字符串形式的JavaScript代码, 但使用时需注意安全性问题) 来执行代码,
// 这个方法可用于动态加载和执行一些脚本片段,例如根据用户操作或者业务逻辑动态添加一些代码逻辑到页面中执行等情况。
globalEval : function ( data ) {
if ( data && jQuery . trim ( data ) ) {
( window . execScript || function ( data ) {
window [ "eval" ] . call ( window , data ) ;
} ) ( data ) ;
}
} ,
// 将字符串从dashed( 使用连字符分隔的, 例如`background-color`这种形式) 转换为camelCase( 驼峰命名法, 例如`backgroundColor`)的方法,
// 首先通过`rmsPrefix`正则表达式替换将以`"-ms-"`开头的字符串替换为`"ms-"`(可能是处理微软浏览器特定前缀相关的样式属性等情况),
// 然后通过`rdashAlpha`正则表达式匹配并结合`fcamelCase`回调函数将字符串中`"-"`后跟字母的部分转换为大写字母, 实现整个字符串的驼峰命名法转换, 常用于处理CSS样式名等转换为JavaScript中合适的属性命名形式等场景。
camelCase : function ( string ) {
return string . replace ( rmsPrefix , "ms-" ) . replace ( rdashAlpha , fcamelCase ) ;
} ,
// 检查元素是否具有指定的节点名称的方法,首先获取元素的`nodeName`属性(表示节点的名称,例如`"DIV"`等),
// 然后将其转换为小写形式与传入的要检查的名称`name`(也转换为小写形式)进行比较,如果相等则返回`true`,表示元素具有指定的节点名称,否则返回`false`,
// 常用于在操作DOM元素时, 根据节点名称来筛选、判断元素是否符合要求等情况。
nodeName : function ( elem , name ) {
return elem . nodeName && elem . nodeName . toLowerCase ( ) === name . toLowerCase ( ) ;
} ,
// 遍历对象或数组的方法,参数`obj`是要遍历的对象或数组,`callback`是一个回调函数,会在每个元素或属性上被调用,
// 首先判断`obj`是否是类似数组的对象(通过`isArrayLike`函数判断,此处代码未完整展示其定义,但通常是判断是否有`length`属性等类似数组特征的对象),
// 如果是类似数组的对象,获取其长度并通过`for`循环遍历每个元素,在每次循环中调用`callback`函数并传入元素的索引和元素本身作为参数,
// 如果`callback`函数返回`false`,则终止循环;如果`obj`不是类似数组的对象,则通过`for...in`循环遍历对象的每个属性,同样调用`callback`函数并传入属性名和属性对应的值作为参数,
// 最后返回遍历的对象或数组本身(方便链式调用等操作),这个方法常用于对集合类型的数据进行统一的操作处理,比如修改元素属性、收集数据等情况。
each : function ( obj , callback ) {
var length , i = 0 ;
if ( isArrayLike ( obj ) ) {
length = obj . length ;
for ( ; i < length ; i ++ ) {
if ( callback . call ( obj [ i ] , i , obj [ i ] ) === false ) {
break ;
}
}
} else {
for ( i in obj ) {
if ( callback . call ( obj [ i ] , i , obj [ i ] ) === false ) {
break ;
}
}
}
return obj ;
} ,
} ) ;
// Support: Android<4.1, IE<9
// 去除字符串两端的空白字符
// `trim`方法用于去除字符串两端的空白字符,如果传入的参数不符合要求则返回空字符串。
// 参数`text`是要进行处理的字符串或者其他可能被转换为字符串的数据。
trim : function ( text ) {
// 如果传入的`text`为`null`或者`undefined`,说明没有有效的字符串内容,直接返回空字符串。
return text == null ?
"" :
// 如果`text`不为`null`和`undefined`,先将其转换为字符串(因为可能传入的是其他类型的数据,比如数字、对象等,通过`+ ""`的方式可以将其转换为字符串表示形式),
// 然后使用之前定义的正则表达式`rtrim`( 用于匹配并去除字符串开头和结尾的空白字符, 包括常见空白字符以及像BOM、不间断空格等特殊空白字符) 进行替换操作, 将匹配到的空白字符替换为空字符串, 从而实现去除两端空白字符的效果, 最后返回处理后的字符串。
( text + "" ) . replace ( rtrim , "" ) ;
} ,
// `makeArray`方法用于将类数组对象(比如`arguments`对象、DOM元素集合等具有类似数组特征但不是真正数组的对象) 或可迭代对象转换为真正的数组, 方便后续使用数组的原生方法进行操作。
// 参数`arr`是要转换的对象,`results`是一个内部使用的参数,用于存储转换的结果,默认情况下如果没有传入该参数则初始化为空数组。
makeArray : function ( arr , results ) {
var ret = results || [ ] ; // 如果没有传入`results`参数,就将`ret`初始化为一个空数组,用于后续存储转换后的元素。
if ( arr != null ) { // 如果传入的`arr`不为`null`或者`undefined`,说明有实际的数据需要进行转换处理。
// 判断`arr`是否类似数组,通过将`arr`转换为对象(使用`Object(arr)`)后再判断其是否具有类似数组的特征(比如有`length`属性等情况,这里假设`isArrayLike`函数用于判断是否类似数组,其具体实现代码未完整展示)。
if ( isArrayLike ( Object ( arr ) ) ) {
// 如果`arr`是类似数组的对象,进一步判断如果`arr`是字符串类型,因为字符串在某些情况下也可以看作是类似数组(每个字符可以看作是数组元素),所以将其放入一个只包含该字符串的数组中(即`[arr]`),这样就把字符串也当作一个元素放入新数组里了;
// 如果`arr`不是字符串类型,直接使用`arr`本身(它已经是类似数组的对象了,比如`NodeList`等,直接合并到结果数组中即可),通过`jQuery.merge`方法(用于合并元素到数组的方法,下面有其具体实现)将处理后的`arr`合并到`ret`数组中。
jQuery . merge ( ret ,
typeof arr === "string" ?
[ arr ] : arr
) ;
} else {
// 如果`arr`不是类似数组的对象,直接使用`push`方法(从之前借用的`deletedIds`数组的`push`方法,用于向数组中添加元素)将`arr`添加到`ret`数组中,使其成为数组中的一个元素。
push . call ( ret , arr ) ;
}
}
return ret ; // 返回转换后的数组,这个数组包含了原来类数组对象或者可迭代对象中的元素,已经转换为真正的数组形式了。
} ,
// `inArray`方法用于判断一个元素是否在给定的数组中,如果在数组中则返回该元素在数组中的索引位置,如果不在则返回 -1, 方便查找元素在数组中的位置情况。
// 参数`elem`是要查找的元素,`arr`是要查找的目标数组,`i`是可选的起始查找索引(用于指定从数组的哪个位置开始查找)。
inArray : function ( elem , arr , i ) {
var len ;
if ( arr ) { // 如果传入的数组`arr`不为空(即不是`null`或者`undefined`),说明有实际的数组进行查找操作。
if ( indexOf ) { // 如果`indexOf`方法存在(在现代浏览器中通常是数组的原生`indexOf`方法可用,这里的`indexOf`应该是之前从`deletedIds`数组借用过来的方法或者类似功能的判断,代码未完整展示其来源情况),
return indexOf . call ( arr , elem , i ) ; // 直接使用`indexOf`方法,通过改变`this`指向(调用`call`方法)为`arr`数组,传入要查找的元素`elem`和可选的起始索引`i`,来查找元素在数组中的索引位置并返回结果。
}
len = arr . length ; // 获取数组`arr`的长度,用于后续循环遍历数组进行查找操作。
i = i ? i < 0 ? Math . max ( 0 , len + i ) : i : 0 ; // 处理传入的起始索引`i`,如果`i`有值,进一步判断如果`i`是负数,通过计算`Math.max(0, len + i)`将其转换为从数组末尾往前计数的正向索引( 确保索引在有效范围内, 最小为0) ; 如果`i`是正数或者为0, 就直接使用传入的`i`作为起始索引,最终确定实际开始查找的索引位置。
// 通过`for`循环从确定好的起始索引位置开始遍历数组,直到遍历完整个数组(索引小于数组长度`len`)。
for ( ; i < len ; i ++ ) {
// 跳过稀疏数组中的空位(在稀疏数组中有些索引位置没有元素,通过`i in arr`判断当前索引`i`是否在数组中有对应的元素定义,只有有对应元素并且元素值与要查找的`elem`相等时才说明找到了目标元素)。
if ( i in arr && arr [ i ] === elem ) {
return i ; // 找到元素后,返回该元素在数组中的索引位置。
}
}
}
return - 1 ; // 如果遍历完整个数组都没有找到目标元素,返回 -1, 表示元素不在该数组中。
} ,
// `merge`方法用于合并两个数组,将第二个数组的元素添加到第一个数组中,实现数组元素的合并操作,常用于合并数据集合等场景。
// 参数`first`是第一个数组,也就是接收要合并元素的目标数组,`second`是第二个数组,即提供要合并进来元素的数组。
merge : function ( first , second ) {
var len = + second . length , // 获取`second`数组的长度, 并将其转换为数字类型( 因为可能在一些情况下长度属性的值不一定是标准的数字, 比如在旧版本IE中对于类数组对象的长度属性可能有特殊情况, 这里先进行转换确保后续操作正确) ,
j = 0 ,
i = first . length ; // 获取`first`数组的长度,用于确定从哪个位置开始添加`second`数组的元素。
// 使用`while`循环,只要`j`( `second`数组的当前索引)小于`len`( `second`数组的长度),就将`second`数组中的元素逐个添加到`first`数组的末尾(通过`first[i++] = second[j++]`操作,先将`second`数组当前索引位置的元素赋值给`first`数组的对应位置,然后两个数组的索引都向后移动一位)。
while ( j < len ) {
first [ i ++ ] = second [ j ++ ] ;
}
// 支持IE<9的情况, 处理类数组对象( 如`NodeLists`)的长度属性可能不是数字的情况,也就是当`len`转换为数字后与自身不相等(说明是`NaN`,可能长度属性的值不符合数字规范)时,
// 通过继续循环,只要`second`数组中当前索引位置的元素`second[j]`不为`undefined`,就继续将其添加到`first`数组的末尾(同样使用`first[i++] = second[j++]`操作),确保所有有效的元素都能被合并到`first`数组中。
if ( len !== len ) {
while ( second [ j ] !== undefined ) {
first [ i ++ ] = second [ j ++ ] ;
}
}
first . length = i ; // 更新`first`数组的长度,使其准确反映合并后数组包含元素的数量。
return first ; // 返回合并后的数组,此时`first`数组已经包含了原来自身的元素以及`second`数组合并进来的元素。
} ,
// `grep`方法使用回调函数对数组进行过滤操作,返回满足条件的元素组成的新数组,可根据回调函数的返回值来筛选出符合特定要求的元素。
// 参数`elems`是要进行过滤的数组,`callback`是一个回调函数,用于定义过滤的条件,`invert`是一个布尔值,用于控制过滤的逻辑(是否取反过滤条件)。
grep : function ( elems , callback , invert ) {
var callbackInverse ,
matches = [ ] ,
i = 0 ,
length = elems . length ,
callbackExpect = ! invert ; // 根据`invert`的值确定`callback`的期望返回值,如果`invert`为`false`(默认情况),则期望`callback`返回`true`时元素符合条件被选中;如果`invert`为`true`,则期望`callback`返回`false`时元素符合条件被选中,通过取反`invert`的值来设置`callbackExpect`这个期望返回值的状态。
// 通过`for`循环遍历要过滤的`elems`数组, 从索引0开始, 直到遍历完整个数组( 索引小于数组长度`length`)。
for ( ; i < length ; i ++ ) {
callbackInverse = ! callback ( elems [ i ] , i ) ; // 调用传入的`callback`回调函数,传入当前元素`elems[i]`和当前索引`i`作为参数,然后对`callback`的返回值取反,得到`callbackInverse`,这一步是根据`invert`参数来调整实际的过滤判断逻辑(如果`invert`为`true`,就相当于取反了原本的过滤条件)。
if ( callbackInverse !== callbackExpect ) { // 如果`callbackInverse`(经过取反调整后的回调函数返回值)与`callbackExpect`(期望的回调函数返回值)不相等,说明当前元素符合过滤条件(根据`invert`参数设定的取反或正常过滤逻辑)。
matches . push ( elems [ i ] ) ; // 将符合过滤条件的当前元素添加到`matches`数组中,用于收集满足条件的所有元素。
}
}
return matches ; // 返回过滤后的数组,这个数组包含了经过回调函数和`invert`参数设定的过滤条件筛选后满足要求的元素。
} ,
// `map`方法用于对数组或对象进行映射操作,也就是对其中的每个元素应用一个回调函数,然后将回调函数处理后的结果组成一个新的数组返回,常用于对数据进行批量转换等操作。
// 参数`elems`是要进行映射操作的数组或对象,`callback`是用于处理每个元素的回调函数,`arg`是可选的额外参数,可传递给回调函数使用(具体看回调函数的实现需求)。
map : function ( elems , callback , arg ) {
var length , value ,
i = 0 ,
ret = [ ] ; // 初始化一个空数组`ret`,用于存储经过回调函数处理后的元素,最终作为映射操作的结果返回。
// 判断`elems`是否是类数组对象(同样假设`isArrayLike`函数用于判断是否类似数组,用于区分不同的数据结构以便采取不同的遍历方式),如果是类数组对象,说明可以按照数组的方式进行遍历操作。
if ( isArrayLike ( elems ) ) {
length = elems . length ; // 获取`elems`的长度,用于控制循环遍历的次数,确保遍历完所有元素。
// 通过`for`循环遍历`elems`数组, 从索引0开始, 每次循环获取当前索引位置的元素`elems[i]`,并将其和索引`i`以及可选的额外参数`arg`一起传入`callback`回调函数进行处理,得到处理后的结果`value`。
for ( ; i < length ; i ++ ) {
value = callback ( elems [ i ] , i , arg ) ;
if ( value != null ) { // 如果回调函数返回的`value`不为`null`或者`undefined`,说明有有效的处理结果,将其添加到`ret`数组中,用于收集所有有效的映射结果。
ret . push ( value ) ;
}
}
} else {
// 如果`elems`不是类数组对象,说明可能是普通对象,通过`for...in`循环遍历对象的所有属性,每次循环获取当前属性对应的元素`elems[i]`,同样将其和属性名(也就是索引`i`)以及可选的额外参数`arg`一起传入`callback`回调函数进行处理,得到处理后的结果`value`。
for ( i in elems ) {
value = callback ( elems [ i ] , i , arg ) ;
if ( value != null ) { // 如果回调函数返回的`value`不为`null`或者`undefined`,将其添加到`ret`数组中,收集所有有效的映射结果。
ret . push ( value ) ;
}
}
}
// 使用concat方法将ret数组中的嵌套数组展平
return concat . apply ( [ ] , ret ) ;
} ,
// 全局GUID计数器, 用于生成唯一标识符
guid : 1 ,
// 绑定函数到指定上下文,并可选地预设一些参数
proxy : function ( fn , context ) {
var args , proxy , tmp ;
// 如果context是字符串, 则假设是要绑定到fn的某个方法上
if ( typeof context === "string" ) {
tmp = fn [ context ] ;
context = fn ;
fn = tmp ;
}
// 检查fn是否为函数, 如果不是则返回undefined
if ( ! jQuery . isFunction ( fn ) ) {
return undefined ;
}
// 保存额外参数
args = slice . call ( arguments , 2 ) ;
// 创建代理函数
proxy = function ( ) {
// 将预设参数和当前调用的参数合并,然后调用原函数
return fn . apply ( context || this , args . concat ( slice . call ( arguments ) ) ) ;
} ;
// 设置代理函数的guid, 以便可以移除事件监听器等
proxy . guid = fn . guid = fn . guid || jQuery . guid ++ ;
return proxy ; // 返回代理函数
} ,
// 获取当前时间的毫秒数
now : function ( ) {
return + ( new Date ( ) ) ; // 返回Date对象的时间戳( 毫秒数)
} ,