【jquery源码五】jQuery工具方法汇总①。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w390058785/article/details/80907640

前言:jQuery的工具方法是jQuery源码中的基石,是构建庞大的jQuery库的根本。这些工具方法也给我们的编程带来了很多便利。

 

【jquery源码】目录

一、修改$.extend()

 

【jquery源码三】jQuery是如何创建方法和扩展方法

前面的文章也说到了$.extend(),$.fn.extend()的作用。我们这里进行简易的修改,一样实现扩展方法的效果。

jQuery.extend = jQuery.fn.extend = function() {
	var options, name, src, copy,
	target = arguments[0] || {},     
	i = 1,     
	length = arguments.length,    

	if ( length === i ) {    
		target = this;    
		--i;              
	}
	for ( ; i < length; i++ ) {  
		if ( (options = arguments[ i ]) != null ) {  	
			for ( name in options ) {
				src = target[ name ];       
				copy = options[ name ];	    				
				target[ name ] = copy;
			}
		}
	}
	return target;
};

二、jQuery工具方法

1、因为工具方法比较多,我们先来看看以下这些工具方法和扩展属性

jQuery.extend({
	noConflict: function(){},
 
	isReady: false,
	readyWait: 1,
	holdReady: function(){},
	ready: function(){},
           
        each: function(obj, callback, args){},
        isFunction: function( obj ){},
	isArray: function(){}, 
	isWindow: function( obj ){},
	isNumeric: function( obj ){},
	type: function( obj ){},
	isPlainObject: function(){},
	isEmptyObject: function( obj ){},
	error: function( msg ){},
	parseJSON: function(){},
	trim: function( text ){}
});

 

 

2、模拟jQuert扩展属性跟方法

 

 

(function(window,undefined){  
	var _$ = window.$,
	    _jQuery = window.jQuery;
		
	var jQuery = function(selector){  
		return new jQuery.fn.init(selector);  
	};  
	jQuery.fn = jQuery.prototype = {  
		jquery:'2.0.3',     //jquery版本号信息
		constructor: jQuery,    //添加构造器属性
		length:0,			//初始length属性
		selector:'',		//初始selector属性
		init: function(selector){   
			if(selector.nodeType){
				this.context = this[0] = selector;
				this.length = 1;	
			}else if(typeof selector === 'function'){
				return jQuery(document).ready(selector);
			}
		},
		ready: function(fn){
			jQuery.ready.promise().done( fn );

			return this;
		},
	}; 
	jQuery.fn.init.prototype = jQuery.fn;  
	
	jQuery.extend = jQuery.fn.extend = function() {
		var options, name, src, copy,
		target = arguments[0] || {},     
		i = 1,     
		length = arguments.length,
		deep = false;     

		if ( length === i ) {    
			target = this;    
			--i;              
		}
		for ( ; i < length; i++ ) {  
			if ( (options = arguments[ i ]) != null ) {  	
				for ( name in options ) {
					src = target[ name ];       
					copy = options[ name ];	    				
					target[ name ] = copy;
				}
			}
		}
		return target;
	};
	
	jQuery.extend({
		noConflict: function(deep){
			if( window.$$ === jQuery ){
				window.$ = _$;	
			}
			if( deep && window.jQuery === jQuery ){
				window.jQuery = _jQuery;	
			}		
			return jQuery;
		},
	
		isReady: false,
		readyWait: 1,
		holdReady: function(){},
		ready: function(){},
	        
                each: function(obj, callback, args){},              
                
                isFunction: function( obj ){},
		
		isArray: Array.isArray,       
	
		isWindow: function( obj ){},
	
		isNumeric: function( obj ){},
	
		type: function( obj ){},
	
		isPlainObject: function(  ){},
	
		isEmptyObject: function( obj ){},
	
		error: function( msg ){},
	
		parseJSON: JSON.parse,
	
		trim: function( text ){}
	});

	window.$$ = window.jQuery = jQuery;    	
})( window ); 


1、noConflict:解决jQuery或$ 命名冲突

 

 

 

①、noConflict的使用例子

<script>
	var $ = '$等待被覆盖';
	var jQuery = 'jQuery等待被覆盖';
	console.log($);	
	console.log(jQuery);
</script>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script>
<script>
	console.log($);	
	console.log(jQuery);
	var $ = '覆盖$';
	var jQuery = '覆盖jQuery';
	console.log($);	
	console.log(jQuery);
	
	$(function(){
		console.log('$失效了');	
	});
</script>
</body>

输出结果:

这时就可以看到,最先定义的$,jQuery跟在引入jquery.js后,就被覆盖了jQuery覆盖了,然后我们再次定义$,jQuery,又把jQuery对象覆盖了,这时候$、jQuery也失效了。这时候就需要用到noConflict了。

<body>
<script>
	var $ = '$等待被覆盖';
	var jQuery = 'jQuery等待被覆盖';
	console.log($);	
	console.log(jQuery);
</script>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script>
<script>
	
	var $$ = $.noConflict();
	console.log($);	
	var wQ = $$.noConflict(true);
	console.log(jQuery);
	
	$$(function(){
		console.log('$$替换了$');	
	});
	wQ(function(){
		console.log('wQ替换了jQuery');
	});
</script>
</body>

输出结果:

这时候就不担心命名冲突问题啦。

②、noConflict实现原理

noConflict: function(deep){
	if( window.$$ === jQuery ){
		window.$ = _$;	
	}
	if( deep && window.jQuery === jQuery ){
		window.jQuery = _jQuery;	
	}		
	return jQuery;
}

在源码头部创建了_$跟_jQuery用来储存在jQuery引入之前-全局创建的$,jQuery的值。然后在noConflict方法中,将之前储存的_$跟_jQuery赋值还给全局的$跟jQuery,然后return出去局部的jQuery对象。

 

2.isReady  3.readyWait  4.holdReady  5.ready

这两个属性跟两个方法设计到$(document).ready()的使用,较为复杂,后面会有单独一篇文章来说他们。

 

6、each 

each相信大家也用的比较多了,用于数组,类数组、对象、json数据的遍历。

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;
		}
	    }
        }
    } else {	//我们外部使用一般走这里
	if ( isArray ) {    //是数组或类数组用for循环
	    for ( ; i < length; i++ ) { 
	        //这里的第一个参数是改变this指向,第二个参数是索引i,第三个参数是值
		//value是callback运行后的返回值
	        value = callback.call( obj[ i ], i, obj[ i ] );  
		if ( value === false ) {
			break;
		}
	    }
        } else { 	//不是数组或类数组的就用for in 循环
	    for ( i in obj ) {
		value = callback.call( obj[ i ], i, obj[ i ] );
		if ( value === false ) {
			break;
		}
	    }
	}
    }
    return obj;	
}

有第三个参数argsr一般都是jQuery源码中为了处理更加复杂的循环的时候用到的,我们现实开发工程中并不常用到。

实验:

<body>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script>
<script>
	var arr = ['nick','freddy','mike'];
	$.each(arr, function(i,item){
		if(item === 'freddy'){
			console.log(item);
			return false;	
		}
		console.log(item);
	});	
</script>
</body>

运行结果:

像这样,设置如果当item===‘freddy’的时候,return false; 源码中遍历到'freddy'的时候value = false。于是触发了break,跳出了循环。

 

7、isFunction(obj)   用于检测传入的参数是否是函数。

这里调用了jQuery.type方法,查看获取到的类型是否与'function'相等

isFunction: function( obj ){
	return jQuery.type(obj) === "function";
}

 

11、type(obj) 用于检测传入参数的数据类型。

 

var class2type = {},
    core_toString = class2type.toString;
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
	class2type[ "[object " + name + "]" ] = name.toLowerCase();
});	

输出class2type来看看

type: function( obj ){
			
    if ( obj == null ) {
	return String( obj );
    }
    
    return typeof obj === "object" || typeof obj === "function" ?
	class2type[ core_toString.call(obj) ] || "object" :
	typeof obj;
}

如有不太明白的朋友可以看看我的这篇文章。

 

【JavaScript】封装可以辨别全部数据类型的方法

 

8、isArray(obj)   用于检测传入的参数是否是数组。

 

isArray: Array.isArray

这里直接引用了原生js中的Array.isArray方法。该ECMAScript5下的用于检测是否是数组,该方法不支持iE6,7,8

 

 

 

9、isWindow(obj)   用于检测传入的参数是否是window对象。

isWindow: function( obj ) {
    return obj != null && obj === obj.window;
}

只有window对象才有名字为window的属性

 

10、isNumeric(obj)   用于检测传入的参数是否是数字类型的

isNumeric: function( obj ) {
    return !isNaN( parseFloat(obj) ) && isFinite( obj );
}

看下以下例子就能看懂该源码了

<body>
<script>
console.log(parseFloat('123a'));
console.log(Number('123a'));
console.log(typeof NaN);
console.log(typeof Infinity);
console.log(isFinite(123));
console.log(isFinite(Infinity));
</script>
</body>

输出结果

这里显示的NaN 还有 Infinity(无穷大数) 的数据类型竟然也是number,这个很不合理。还有的是,parseFloat('123a')竟然把该字符串转成了123数字,我觉得该源码不是很合理,所以我改成了以下代码。

isNumeric: function( obj ){
	return !isNaN( Number(obj) ) && isFinite( obj );	
}

 

12、isPlainObject(obj) 用于检测传入的参数是否是对象自变量,也是我们常说的json格式对象

 

js中的对象还是蛮多了,例如DOM节点对象,还有window对象,window.location

isPlainObject: function(obj){
    if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
	  return false;
    }	
    return true;
}

DOM节点对象都有nodeType属性

 

13、isEmptyObject  用于检测传入的参数是否是空对象

isEmptyObject: function( obj ) {   //判断是否为空的对象
    var name;
    for ( name in obj ) {
	return false;
    }
    return true;
}

空对象不能进行for in循环

 

14、error 用于在控制台输出错误信息

error: function( msg ){
    throw new Error( msg );	
}
<body>
<script>
    throw new Error('这是错误信息');
</script>
</body>

输出结果:

 

15、parseJSON 用于将字符串转成JSON格式数据

parseJSON: JSON.parse

这里也是直接引用了原生js中的JSON.parse方法。

 

16、trim 用于去除'   string   '前后空格

trim: function( text ) {
    return text == null ? "" : "".trim.call( text );
}
<body>
<script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script>
<script>
var str = ' string ';
console.log(str.length);
console.log($.trim(str).length);
</script>
</body>

输出结果:

 

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页