基于jquery-2.0.3的源码分析
//4.jQuery.extend() : 扩展一些工具方法
/*jQuery.extend({
expando : 生成唯一JQ字符串(内部)
noConflict() : 防止冲突
isReady : DOM是否加载完(内部)
readyWait : 等待多少文件的计数器(内部)
holdReady() : 推迟DOM触发
ready() : 准备DOM触发
isFunction() : 是否为函数
isArray() : 是否为数组
isWindow() : 是否为window
isNumeric() : 是否为数字
type() : 判断数据类型
isPlainObject() : 是否为对象自变量
isEmptyObject() : 是否为空的对象
error() : 抛出异常
parseHTML() : 解析节点
parseJSON() : 解析JSON
parseXML() : 解析XML
noop() : 空函数
globalEval() : 全局解析JS
camelCase() : 转驼峰(内部)
nodeName() : 是否为指定节点名(内部)
each() : 遍历集合
trim() : 去前后空格
makeArray() : 类数组转真数组
inArray() : 数组版indexOf
merge() : 合并数组
grep() : 过滤新数组
map() : 映射新数组
guid : 唯一标识符(内部)
proxy() : 改this指向
access() : 多功能值操作(内部)
now() : 当前时间
swap() : CSS交换(内部)
});
*/
jQuery.extend({
//生成唯一的jq字符串(内部),作用:用于作为唯一映射关系
expando:"jQuery" + (core_version + Math.random()).replace(/\D/g, ""),
//防止冲突,当外界使用 $ 或者 jQuery 时候,jq可以自动方法这两个对外接口,通过调用 noConflict()函数,自定义对外使用接口
noConflict:function(deep){
if(window.$ === jQuery){ //不写参数的时候是对$的放弃写参数的时候是对jQuery的放弃
window.$ = _$; //不写参数的时候放弃$
}
if(deep && window.jQuery === jQuery){
window.jQuery = _jQuery;
}
return jQuery;
/*noConflict()的使用
*/
},
isReady: false, //dom是否加载完成(内部使用)
readyWait:1,//等待多少文件的计数器(内部)
holdReady:function(hold){ //推迟DOM触发
if(hold){
jQuery.readyWait ++;
}else{
jQuery.ready(true);
}
},
ready:function(wait){ //准备DOM触发,参数和holdReady有关
//如果readyWait不是0,或者isReady是false,那么什么也不做,继续等待!
//readyWait为0时就不用hold了,执行后面的操作
if(await === true ? --jQuery.readyWait : jQuery.isReady){
return;
}
jQuery.isReady = true;//默认是false
if(wait !==true && --jQuery.readyWait >0){
return;
}
//如果已经readyWait是0,那么就会执行,也就是触发事件,最终调用Deferred对象的done方法
//上下文是document,第二个参数是jQuery对象!这时候外层的done已经执行了,也就说这个ready中的函数可以执行了!
//第一个参数是指向context所以ready中第一个参数是document对象,第二个jQuery就是参数也就是给ready函数传递的参数!
readyList.resolveWith( document, [ jQuery ] );
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger("ready").off("ready");
}
},
isFunction:function(obj){//是否为函数
return jQuery.type(obj) === "function";//$.type() 函数用于确定JavaScript内置对象的类型,并返回小写形式的类型名称。
},
isArray:Array.isArray,//是否为数组
isWindow:function(obj){ //是否为window
return obj != null && obj === obj.window;
},
isNumeric:function(obj){ //是否为数字
//isNaN() 函数用于检查其参数是否是非数字值
//parseFloat() 函数可解析一个字符串,并返回一个浮点数。
//该函数指定字符串中的首个字符是否是数字。如果是,则对字符串进行解析,直到到达数字的末端为止,然后以数字返回该数字,而不是作为字符串。
//isFinite() 函数用于检查其参数是否是无穷大。
return !isNaN( parseFloat(obj) ) && isFinite(obj);
},
type:function(obj){ // 判断数据类型
if(obj == null){
return String(obj);
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[core_toString.call(obj)] || "object" : typeof obj;
},
isPlainObject:function(obj){ //是否为对象自变量
if(jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow(obj)){
return false;
}
try{
if(obj.constructor && !core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){
return false;
}
}catch(e){
return false;
}
},
isEmptyObject:function(obj){ //判断是否为空的对象
//for-in循环会同时枚举非继承属性和从原型对象继承的属性,如果有,则立即返回false,否则默认返回true。
var name;
for(name in obj){ //for...in 语句用于对数组或者对象的属性进行循环操作。
return false;
}
return true;
},
error:function(msg){ //抛出异常
throw new Error( msg );
},
parseHTML:function(data,context,keepScripts){ //解析节点
if(!data || typeof data !== "string"){
return null;
}
//只有两个参数的时候,第二个就是是否保存script标签,这时候context就没有传进来
if(typeof context === "boolean"){
keepScripts = context;
context = false;
}
//如果只有两个参数那么context就是document对象!
context = context || document;
//如果不是单个标签那么parsed就是null,所谓的单个标签就是或者但是hello不满足!
var parsed = rsingleTag.exec( data ),
//如果keepScripts是false,那么scripts就是
scripts = !keepScripts && [];
if ( parsed ) {
//如果是单个标签就调用相应的createElement方法,默认上下文是document!
return [ context.createElement( parsed[1] ) ];
}
//如果不是单个标签就调用buildFragment方法,把html字符串传入,同时上下文也传入,第三个参数就是scripts!
//如果paseHTML的第三个参数是false,那么这里的scripts就是一个数组,传递到buildFragment中会把所有的script标签放在里面
parsed = jQuery.buildFragment( [ data ], context, scripts );
if(scripts){
jQuery(scripts).remove();
}
//buildFragment返回的是文档碎片,所以要变成数组,调用merge方法
return jQuery.merge( [], parsed.childNodes );
},
parseJSON: JSON.parse,//解析JSON
parseXML:function(){ //解析XML
var xml, tmp;
if ( !data || typeof data !== "string" ) {
return null;
}
// Support: IE9
try {
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} catch ( e ) {
xml = undefined;
}
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
},
noop:function(){}, //空函数
globalEval:function(code){ //全局解析JS
// code:待执行的JavaScript语句或表达式
var script,
indirect = eval;
code = jQuery.trim(code);//去除字符串的前后空格
if(code){
//indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
//如果在数组中没找到字符串则返回 -1
if(code.indexOf("use strict") === 1 ){ //判断是否是在严格模式下,严格模式不支持eval
//createElement() 方法通过指定名称创建一个元素
script = document.createElement("script");
script.text = code;
document.head.appendChild( script ).parentNode.removeChild( script );
}else{
indirect(code);
}
}
},
camelCase:function(string){ //转驼峰(内部)
return string.replace(rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
nodeName:function(elem,name){ //是否为指定节点(内部使用)
//用法$.nodeName(document.body,'html')
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
each: function( obj, callback, args ) {//遍历集合
var value,
i = 0,
length = obj.length,
isArray = isArraylike( obj );
if ( args ) {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.apply( obj[ i ], args );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.apply( obj[ i ], args );
if ( value === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
}
}
return obj;
},
trim:function(text){ //去前后空格
return text == null ? "" : core_trim.call( text );
},
makeArray:function(arr,results){ //类数组转真数组
// makeArray可以将一个类数组转换成真正的数组。如果传入第二个参数resullts(仅在jQuery内部使用),
//第一个参数arr中的元素将被合并入第二个参数,最后返回第二个参数,此时返回的不一定是真正的数组。
// 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{
core_push.call(ret,arr);
}
}
// 返回ret
return ret;
},
//jQuery.inArray()函数用于在数组中搜索指定的值,并返回其索引值。如果数组中不存在该值,则返回 -1。
inArray:function(elem,arr,i){ // 数组版 indexOf
return arr == null ? -1 : core_indexOf.call(arr,elem,i);
},
merge:function(first,second){ //合并数组
// 用于合并两个数组的元素到第一个数组中,第一个参数可以是数组或类数组对象,即必须含有整数(或可以转换成整些)属性length;
//第二个参数可以数组,类数组对象或任何含有连续属性的对象。注意:方法jQuery.merge()的合并具有破坏性,
//将第二个参数合并到第一个参数时,会改变第一个参数。如果不希望改变第一个参数,可以在调用jQuery.merge()方法前对第一个参数进行备份。
// 初始化变量,将second.length转换成数字,
//并将first.length赋值给i,循环添加second的属性到first中,因为不确定first是否是数组,所以用i来修正first.length。最后返回first。
var l = second.length,
i = first.length,
j = 0;
if(typeof l ==="number"){ //判断第二个参数是数组
for(;j