前言:上篇文章已經分析了16個常用工具方法了,現在來繼續分析後面的17個常用工具方法。
【jquery源碼】目錄
【jquery源碼五】jQuery工具方法彙總①。
一、工具方法
jQuery.extend({
parseHTML: function( data, context, keepScripts ){},
parseXML: function( data ){},
noop: function() {},
globalEval: function( code ){},
camelCase: function( string ){},
nodeName: function( elem, name ){},
makeArray: function( arr, results ){},
inArray: function( elem, arr, i ){},
merge: function( first, second ){},
grep: function( elems, callback, inv ){},
map: function( elems, callback, arg ){},
guid: 1,
proxy: function( fn, context ){},
access: function( elems, fn, key, value, chainable, emptyGet, raw ){},
now: Date.now,
swap: function( elem, options, callback, args ){},
buildFragment: function(){}
});
二、工具方法分析。
9、merge(先講第9個的merge方法,因為下面中很多地方會用到)
①、merge用法,用于數組、類數組、特殊json格式(鍵值為0、1...)的合并。
<script>
var arr1 = ['a','b'];
var arr2 = ['a','b'];
var arr3 = ['a','b'];
var arr4 = ['c','b'];
var json1 = {
0:'e',
1:'f',
length: 2
}
var json2 = {
0:'g',
1:'h'
}
console.log($.merge(arr1,arr4));
console.log($.merge(arr2,json1));
console.log($.merge(arr3,json2));
</script>
輸出結果
②、merge源碼
merge: function( first, second ) { //合并數組
var l = second.length,
i = first.length,
j = 0;
//如果第二個參數的length是數字類型,json格式有legth屬性的也走這裡
if ( typeof l === "number" ) {
for ( ; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) { //json格式的沒有length屬性的走這裡
first[ i++ ] = second[ j++ ];
}
}
first.length = i; //修改合并後的length值
return first;
}
1、parseHTML
①、parseHTML用法,将字元串轉化成節點。
<body>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script>
<script>
var html1 = '<li></li>';
var html2 = '<li></li><li></li><script><\/script>';
console.log($.parseHTML(html1)); //第二個參數指定根節點,預設指定document。
console.log($.parseHTML(html2,document)); //第二個參數指定根節點,有時候有指定到iframe的情況
console.log($.parseHTML(html2,document,true)); //第三個參數是否建立script标簽。預設為false
console.log($.parseHTML(html2,true)); //如果第二個參數為布爾值,源碼中會把布爾值轉到第三個參數
</script>
</body>
輸出結果
像這樣,建立了DOM節點,并包裹在了數組裡面。
②、parseHTML源碼
var rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/; //比對标簽<xxx></xxx>
parseHTML: function( data, context, keepScripts ) {
if ( !data || typeof data !== "string" ) { //如果值為空或者值不是string類型,return null
return null;
}
if ( typeof context === "boolean" ) { //當二個參數是布爾值的時候,将第二個參數轉到第三個參數
keepScripts = context;
context = false;
}
context = context || document; //指定根節點(有時候要填入的是iframe中的document)
var parsed = rsingleTag.exec( data ), //判斷是否是單标簽<div></div>
scripts = !keepScripts && []; //如果keepScript沒有值或者為false,則scripts=[]
//如果keepScript的值true,即scripts = false
// Single tag
if ( parsed ) {
return [ context.createElement( parsed[1] ) ]; //單标簽直接建立節點
}
parsed = jQuery.buildFragment( [ data ], context, scripts ); //建立文檔碎片的形式建立DOM節點
//$.parseHTML(html2,document) -> jQuery.buildFragment( ['<li></li><li></li><script><\/script>'], document, []);
//$.parseHTML(html2,document,true) ->jQuery.buildFragment( ['<li></li><li></li><script><\/script>'], document, false);
if ( scripts ) { //scripts = []; 為true
jQuery( scripts ).remove(); //移除scripts節點
}
return jQuery.merge( [], parsed.childNodes ); //通過jQuery.merge進行合并
}
</script>
$.parseHTML(html2,document) 最終是走-》
jQuery.buildFragment( ['<li></li><li></li><script><\/script>'], document, []);
$.parseHTML(html2,document,true) 最終是走-》
jQuery.buildFragment( ['<li></li><li></li><script><\/script>'], document, false);
接下來看看jQuery.buildFragment的源碼。
17、buildFragment
①、buildFragment用法,将字元串轉化成節點。(這方法一般是jQuery内部使用)
var html2 = '<li>1</li><li>2</li><script>console.log(123)<\/script>';
console.log($.buildFragment([html2],document,[]));
console.log($.buildFragment([html2],document,false));
輸出結果
2、parseXML
①、parseXML用法,将XML格式資料轉化成DOM節點。
var xml = "<rss version='2.0'><channel><title>xml Msg</title></channel></rss>";
var xmlDoc = $.parseXML(xml);
console.log(xmlDoc);
輸出結果
②、parseXML源碼。
parseXML: function( data ) {
var xml, tmp;
if ( !data || typeof data !== "string" ) { //資料必須不為空,并且必須為字元串類型
return null;
}
// Support: IE9
try {
tmp = new DOMParser(); //建立解析XML的一個執行個體對象(原生js)IE8及IE8以下不支援
xml = tmp.parseFromString( data , "text/xml" ); //原生js建立DOM對象
} catch ( e ) {
xml = undefined; //如果出錯資料有錯,IE9會走這裡
}
//如果報錯Firefox建立一個<parsererror>這裡是錯誤資訊</parsererror>标簽
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data ); //輸出錯誤資訊
}
return xml;
}
3、noop
①、noop就是一個空函數,沒有實際意義。
相當于我們建立一個變量,并且這個變量,在後面的程式中會被指派成string類型。這時我們習慣在程式頭部var str = "" 這樣去初始化這個變量。
4、globalEval
①、globalEval,是用來将局部變量變成全局的。
function fn(){
//var msg = "局部的";
$.globalEval('var msg = "局部的";');
}
fn();
console.log(msg);
輸出結果
②、globalEval源碼。
globalEval: function( code ) {
var script,
indirect = eval;
code = jQuery.trim( code );
if ( code ) {
if ( code.indexOf("use strict") === 1 ) { //如果嚴格模式建立script标簽
script = document.createElement("script");
script.text = code;
document.head.appendChild( script ).parentNode.removeChild( script );
} else { //非嚴格模式用eval
indirect( code );
}
}
}
這裡需要注意的是,在代碼中直接用eval()去解析代碼,沒辦法把代碼解析到全局,但是通過window.eval()或者像源碼中把eval指派給一個變量,也可以。
5、camelCase
①、camelCase,是用來将有"-"的參數轉成駝峰形式。例如font-size轉成fontSize
var str1 = "font-size";
var str2 = "-ms-flex";
var str3 = "-o-flex";
var str4 = "-moz-flex";
var str5 = "-webkit-flex";
console.log($.camelCase(str1));
console.log($.camelCase(str2));
console.log($.camelCase(str3));
console.log($.camelCase(str4));
console.log($.camelCase(str5));
輸出結果
這裡需要注意的是“-ms-flex”最終被轉成msFlex,但是“-webkit-flex”最終被轉成了WebkitFlex,這就是-ms-字首與其他浏覽器字首的差別了。
②、camelCase源碼。
var rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi,
fcamelCase = function(all,letter){
return letter.toUpperCase();
};
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
//第一個replace把-ms-替換成ms, 第二個replace把-webkie替換成Webkit,把-size替換成Size
}
replace中的回調函數fcamelCase = function( all, letter ){},第一個參數是正則擷取到整體部分,第二個參數就是正則擷取到的子項。例如-webkit-flex擷取到的all、letter為
6、nodeName
①、nodeName檢測DOM節點的名字
<body>
<div></div>
<script>
var oDiv = document.getElementsByTagName('div')[0];
console.log($.nodeName(document.documentElement, 'html'));
console.log($.nodeName(document.body, 'body'));
console.log($.nodeName(oDiv, 'div'));
</script>
</body>
輸出結果
②、nodeName源碼。
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
}
7、makeArray
①、makeArray 是把其他資料類型轉成數組類型
<body>
<div>1</div>
<div>2</div>
<script>
var num = 123;
var str = 'freddy';
var aDiv = document.getElementsByTagName('div');
var json = {
say: function(){
console.log(123);
}
};
console.log( $.makeArray(num) );
console.log( $.makeArray(str) );
console.log( aDiv );
console.log( $.makeArray(aDiv) ); //将類數組轉換成數組
console.log( $.makeArray(num,json)); //第二個參數傳入json格式,一般是jQuery源碼内部使用
</script>
</body>
輸出結果
②、makeArray 源碼
makeArray: function( arr, results ) { //轉成數組
var ret = results || [];
if ( arr != null ) {
if ( isArraylike( Object(arr) ) ) { //判斷是否類數組,而且isArraylike隻能判斷對象類型的參數(string類型也會走這裡)
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
[].push.call( ret, arr ); //直接push到數組裡
}
}
return ret;
}
8、inArray
①、inArray 其實就是引用了數組方法中的indexO方法
inArray: function( elem, arr, i ) { //i是查找的索引起始位置
return arr == null ? -1 : [].indexOf.call( arr, elem, i );
}
10、grep
①、grep用法 過濾數組中的資料,并得到新數組
其實原生ECMA5中已經有了數組方法[].fiilter(funciton(item, index, array){})方法了。而這個jQuery版本中并沒引用filter方法。
var arr = [1,2,3,4,5];
var arr2 = arr.filter(function(item,index,array){ //原生js數組方法,filter方法
return item>2;
});
var arr3 = $.grep(arr, function(item,index){
return item>2;
});
console.log(arr2);
console.log(arr3);
②、grep 源碼(除了引用filter方法外,我們可以看看,jQuery中是怎樣實作這方法的)
grep: function( elems, callback, inv ) { //過濾數組中的資料,并得到新數組
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv; //第三參數如果為true,就是取反的意思
//比如我要擷取到數組中大于2的值,如果為true擷取到的就是小于2的值。
for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
}
11、map
①、map用法 處理數組中的資料,并得到新數組
同樣,原生ECMA5中已經有了數組方法[].map(funciton(item, index, array){})方法了。而這個jQuery版本中并沒引用map方法。
var arr = [1,2,3,4,5];
var arr2 = arr.map(function(item,index,array){ //原生js數組方法 map方法
return item*2;
});
var arr3 = $.map(arr, function(item,index){
return item*2;
});
console.log(arr2);
console.log(arr3);
②、map 源碼(除了引用map方法外,我們可以看看,jQuery中是怎樣實作這方法的)
map: function( elems, callback, arg ) { //第三參數是jQuery源碼内部使用
var value,
i = 0,
length = elems.length,
isArray = isArraylike( elems ),
ret = [];
if ( isArray ) { //數組,類數組走這裡
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
} else { //特殊json走這裡
for ( i in elems ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
}
return core_concat.apply( [], ret );
}
12、guid
①、guid是給事件函數添加一個唯一的辨別符的,每個事件函數的guid屬性值都是不一樣的。
13、proxy
①、proxy 是用于改變this指向的。
var name = 'window';
var sayName = function(){
console.log(this.name);
}
var freddy = {
name: 'freddy',
};
sayName();
$.proxy(sayName,freddy)();
②、proxy 源碼。
proxy: function( fn, context ) {
var tmp, args, proxy;
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
args = core_slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
};
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
}
15、now
①、now 是用于擷取目前時間的方法。
②、now源碼
now: Date.now //直接引用原生js的Date.now方法