【jquery源码五】工具方法汇总②。 【jquery源码】目录 【jquery源码五】工具方法汇总①。

前言:上篇文章已经分析了16个常用工具方法了,现在来继续分析后面的17个常用工具方法。

【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方法







猜你喜欢

转载自blog.csdn.net/w390058785/article/details/80984753
今日推荐