jQuery的工具方法,也就是jQuery对象的静态方法,直接以$.functionName
的方式进行调用。通过这些方法,极大的提升了我们的开发效率。由于这部分方法比较多,单个方法也比较容易理解,所以,我不打算在本篇文章中对他们进行逐一讲解,只一些我自己感觉设计比较精彩的地方做一些补充和说明。
一、工具方法简化结构
由于源码长度过长,所以我们还是以列出结构的方式,庖丁解牛般的理解这部分代码。
jQuery.extend({
expando: 生成唯一的jQuery字符串(内部)
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.ready.promise = function(){}; 监控DOM的异步操作(内部)
function isArraylike(){} 类似数组的判断
二、jQuery工具方法的使用
1. expando 生成唯一的jQuery字符串
expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
// 使用
$.expando
2. noConflict 防冲突
所谓防冲突,我们要理解怎么个防止法。jQuery中的防冲突方法就是当其他的第三库使用了或者jQuery。没错,就是放弃,另起一个名字。够伟大吧,或许我们可以把这种方式运用到我们的生活中,放弃设计另一种新生!
2.1 用法及源码分析
jQuery初始化中定义的变量
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
jQuery初始化的赋值操作
window.jQuery = window.$ = jQuery;
源码:
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
使用1
var miaov = $.noConflict()
var $ = 123
miaov(function(){
alert($) // 123
})
因为var $ = 123
在$.noConflict()
后面调用,所以window.$ !== jQuery
,window.jQuery === jQuery
,因为这两行代码在jQuery初始化的过程中已经被执行了。结合源码,我们可以知道这时$
的值已经是123
了,只有window.jQuery
依然坚挺,并将其赋值于的miaov
。所以miaov
便代理了$
的
使用2
上面的代码会执行源码中的第一个if条件循环。执行顺序是
var $ = 123 //步骤1
var $ = jQuery = function(){} //步骤2
var maiov = $. noConflict() //步骤3
在执行步骤2,加载jquery库时间,在jquery库的第38、41行分别执行以下代码:
// 也就是将在加载jquery库之前定义的$和jquery,在例子中的123、456保存在变量_jQuery 和变量_$
var
_jQuery = window.jQuery,
_$ = window.$
使用3
这种用法是上一用法的增强版,通过传递第二个参数(boolean)来确定是否改变window.jQuery的值。
3. holdReady 等待多少文件的计数器
3.1 用法
//在添加上下面的一行代码时,下面的代码不会再执行
$.holdReady(true)
// 在添加上一行代码的情况下,再添加上下面的代码,程序完整执行
$.holdReady(false)
$(function(arg){
alert('123')
})
/* a.js */
// 下面的代码运行结果,先弹出2,再弹出1,这是因为getScript函数异步加载了a.js
alert('1)
$.getScript('a.js',function(){ })
$(function(){
alert(2)
})
可以通过holdReady()方法来解决这个异步加载造成的问题
$.holdReady(true)
$.getScript('a.js',function(){
$.holdReady(false)
})
$(function(){
alert(2)
})
3.2 源码分析
holdReady: function( hold ) {
//当传递的参数为true时,变量readyWait递增
if ( hold ) {
jQuery.readyWait++;
} else {
// 当不传参数时,会执行jQuery.ready()
jQuery.ready( true );
}
},
4. isReady DOM是否加载完
4.1比较下面的两种事件加载
$(function(){ }) // 第一种方式
window.onload= function(){ } //第二种方式
第一种方式方式其实使用的是DOMContentLoaded这个事件,这个事件只需要网页结构加载完成后就可被触发。
第二种方式onload会等到网页加载完成并且页面中的资源(图片等)下载完成后再触发。
4.2 jQuery中事件的执行流程
1.$(function(){ })
2.$(document).ready(function(){ })
3.$().ready()
4.jQuery.ready.promise().done( fn )
5.if (document.readyState === 'complete') {
} else {
completed
}
6.readyList.resolveWith( document, [jQuery])
7.执行fn函数。
第1、2、3步都是对函数之间的相互引用。
第4、5步查看819-840行代码
jQuery.ready.promise = function( obj ) {
if ( !readyList ) {
readyList = jQuery.Deferred();
if ( document.readyState === "complete" ) {
setTimeout( jQuery.ready );
} else {
document.addEventListener( "DOMContentLoaded", completed, false );
window.addEventListener( "load", completed, false );
}
}
return readyList.promise( obj );
};
在第一次只执行的时候,readyList为空,会执行整个if函数,给readyList赋值延迟对象,这个函数最后会返回一个promise对象,它的作用是不让外部修改readyList的状态,原理后面再续。
在内层的循环中
if ( document.readyState === "complete" ) {
//document.readyState === 'complete'时,页面完全加载
//此处使用setTimeout为了兼容ie
setTimeout( jQuery.ready );
} else {
//页面在没有完全加载的时,监测DOMContentLoaded和load事件
document.addEventListener( "DOMContentLoaded", completed, false );
window.addEventListener( "load", completed, false );
}
上面的代码中,在页面没有完全加载的时候,同时监听了DOMContentLoaded和load事件,这是因为,load事件会被缓存,所以此处的操作表示,那个事件被触发的早就执行哪个事件。事件的触发之后,会调用completed函数。completed函数的源码如下:
// 解绑定DOMContentLoaded和load事件,并且执行jQuery.ready()
completed = function() {
document.removeEventListener( "DOMContentLoaded", completed, false );
window.removeEventListener( "load", completed, false );
jQuery.ready();
};
第6步 jQuery.ready()
jQuery.ready()函数中有这么一行代码(line:398)
// 这行代码为第4步中的fn函数指定执行环境(document)和传入参数(jQuery)
eadyList.resolveWith( document, [ jQuery ] );
//可以编写如下测试代码
$(function(arg){
alert(this) //[object HTMLDocument]
alert(arg) //jQuery构造函数
})
4.3 ready方法详解
ready: function( wait ) {
//block1
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
jQuery.isReady = true;
//block2
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
//block3
readyList.resolveWith( document, [ jQuery ] );
//block4
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger("ready").off("ready");
}
},
4.31 block1
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
jQuery.isReady = true;
在源码中调用ready函数的时候一般都是$.ready()这样的形式,也就是ready函数的wait=false,由于jQuery.isReady默认为false,所以第一次执行是不执行这个if块中的代码的,第二次才会执行,但是要在jQuery.readyWait大于0的情况下。
这种机制是为了解决下面这种问题
$.holdReady(true)
$.getScript('a.js',function(){
$.holdReady(false)
})
$.holdReady(true)
$.getScript('a.js',function(){
$.holdReady(false)
})
$.holdReady(true)
$.getScript('a.js',function(){
$.holdReady(false)
})
上面的代码执行了三次.holdReady()把jQuery.readyWait的值递减为0时,才表明DOM准备好了,就可以执行函数了。
4.33 block3 处理内部jQuery.ready(true)的情况,逻辑与4.3.2相同。
4.34 block4 以事件的方式调用ready函数
除了下面两种方式触发初始化事件,还有第三种方式,block4的代码
//方式1
$(function(){ })
//方式2
$(document).ready(function(){ })
//方式3
$(document).on('ready', function(){
})
5、isFunction 判断是不是函数
源码以及使用如下
// 调用了jQuery.type函数
isFunction: function( obj ) {
return jQuery.type(obj) === "function";
},
// 用法
function show(){}
var show1 = function(){}
$(function(){
alert($.isFunction(show)) // true
alert($.isFunction(show1)) // true
})
6、isArray 判断是不是数组
// 这个直接调用了原生的函数
isArray: Array.isArray,
7、isWindow 判断是不是window对象
isWindow: function( obj ) {
return obj != null && obj === obj.window;
},
js中的window有两种意义,第一种是作为全局对象,第二种是作为窗口对象。
对于这两个条件的讲解如下:
// undefinded == null // true
// null == null // true
obj != null
当这个条件成立时,就会排除obj是undefinded和null的可能,进入第二个条件
obj === obj.window
//本着只有对象才有属性的概念,如果obj === obj.window时,就可以断定是window对象。
8、isNumeric判断是不是number类型
//原则
// 非Nan
// 有限
isNumeric: function( obj ) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
9、type 判断数据类型
9.1 用法
alert($.type('antiai')) // string
alert($.type(null)) // null
alert($.type(undefined)) //undefinded
alert($.type([])) //array
alert($.type({})) //object
9.2 源码解读
type: function( obj ) {
if ( obj == null ) {
return String( obj );
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[ core_toString.call(obj) ] || "object" :
typeof obj;
}
9.2.1 传入的参数如果是 null 或者undefinded,会进入第一个循环,原样输出。
9.2.2 通过typeof判断出来的结果如果是object || function,则会说明它是复杂的引用类型,进行class2type[ core_toString.call(obj) ] || "object" 运算,如果不是,则说明它是基本数据类型,则进行typeof obj操作即可。
关于class2type[ core_toString.call(obj) ]操作,介绍如下:
//class2type[ core_toString.call(obj) ]
//在源码844-846行为class2type保存了一些值
//执行这段代码后,class2type的保存的值的格式如下截图
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
再对core_toString.call(obj) 进行分析
// line56
core_toString = class2type.toString,
//使用
alert({}.toString.call({})) //[object Object]
alert({}.toString.call([])) //[object Array]
alert({}.toString.call(function(){})) //[object Function]
从返回值,我们就可以知道它的使用用途了。
10.isPlainObject判断是否为对象字面量
10.1用法
var obj = {}
alert($.isPlainObject(obj)) // true
alert($.isPlainObject(new Object())) // true
alert($.isPlainObject([])) // false
10.2 源码解析
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;
}
return true;
}
10.2.1 首先判断当传入的参数满足下面的三个条件,便返回false。
//1、不是对象
jQuery.type( obj ) !== "object"
//2、是DOM节点
obj.nodeType
//3、是window对象
jQuery.isWindow( obj )
10.2.2 接着判断 这个对象不是是满足下面的两个条件,如果都不足,就返回false
// 有原型
obj.constructor
var obj = {}
console.log(obj.constructor) //Object构造函数
//line:57 core_hasOwn = class2type.hasOwnProperty,
// 根据上面的推导结果可知,下面的两行代码是等价的
core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" )
Object.prototype.hasOwnProperty('isPrototypeOf') //true
11、isEmptyObject 是否为空对象
11.1 用法
alert($.isEmptyObject({})) // true
alert($.isEmptyObject({name: 'antiai'})) // false
function Aaa(){}
var aaa = new Aaa()
alert($.isEmptyObject(aaa)) // true
function Bbb(){
this.func = function(){}
}
var bbb = new Bbb()
alert($.isEmptyObject(bbb)) // false
function Ccc(){}
Ccc.prototype.func = function(){}
var ccc = new Ccc()
alert($.isEmptyObject(ccc)) // false
11.2 源码分析
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
}
return true;
},
这段代码主要运用了对象的for...in 循环,for ... in循环只能遍历出挂在对象自生上面的属性和方法并且是自定义的,而不能遍历处原型上面的方法。
13、error抛出错误
13.1 用法
$.error('this is error')
13.2 源码分析
error: function( msg ) {
throw new Error( msg );
},
14、parseHTML 解析节点
14.1 用法
var str = '1 2