jQuery中的extend()实现原理,如何实现深拷贝(递归赋值)

本文详细解析了 jQuery 中 extend 方法的工作原理及其实现细节,包括如何处理不同类型的输入参数,实现浅拷贝和深拷贝的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大致过程:对后一个参数进行循环,然后把后面参数上所有的字段都给了第一个字段,若第一个参数里有相同的字段,则进行覆盖操作,否则就添加一个新的字段
1)对第一个参数做判断,如果不是Boolean类型,且只有一个参数,那么就把jQuery作为target,然后把第一个参数上的字段都赋给target,最后返回target(浅拷贝);如果有多于一个参数,那么第一个参数就是target,然后把后面参数的字段都赋给target,最后返回target(浅拷贝)

2)第一个参数是boolean类型,表示深浅拷贝,true表示深拷贝,false表示浅拷贝。只有两个参数,那么就把jQuery作为target,把第二个参数的字段赋给target,然后返回target。多于两个参数,把第二个参数作为target,然后把后面的参数的字段赋给target,最后面返回target.

具体思路:

1)保存第一个参数到target变量中,如果没有参数则target={},将变量i初始化为1,用变量length保存实际传参个数,变量deep初始化为false(用于判断是否为深度遍历)

2)接着判断第一个参数即target是否为boolean类型,如果是的话,将第一个参数即target赋值给deep,target的值变成第二个参数的值,如果没有第二个参数,那么target={},修改i=2。如果不是直接跳到第3)步

3)如果目标参数即target既不是Object也不是Function,那么target={}

4)如果目标参数target后面没有参数了(i=1或者第一个参数为boolean类型的有2个参数的情况,i = length判断),则目标对象target=this表示jQuery对象,而target表示的参数不在是目标对象,此时i–。【一个参数且为对象i=0;两个或以上对象参数i=1;有两个参数第一个参数为Boolean第二个为object,i=1;有两个或以上参数,第一个为Boolean,剩下的为object,i=2】

5)从下标i开始,对参数进行遍历, 如果参数不为空对象,那么对对象的属性进行遍历

a) 若参数中字段的值就是目标参数,停止赋值,防止无限的循环嵌套

var _default = {name : 'wenzi'};
 var obj = {name : _default}
 $.extend(_default, obj);
 console.log(_default);

b) 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值

c) 若copy是简单的类型且存在值,则直接进行赋值

6)返回target

源码如下:

// 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推
jQuery.extend = jQuery.fn.extend = function() {
	var options, 
	 	name, 
	 	src, 
	 	copy, 
	 	copyIsArray, 
	 	clone,
	    target = arguments[0] || {}, // 默认第0个参数为目标参数
	 	i = 1, // i表示从第几个参数开始将目标参数与其进行合并,默认从第1个参数开始向第0个参数进行合并
	 	length = arguments.length,
		deep = false; // 默认为浅拷贝
	 
	// 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false
	// 同时将第1个参数作为目标参数,i从当前目标参数的下一个
	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
	    deep = target;
 
 		// Skip the boolean and the target
 		// 如果第一个参数是Boolean类型
 		target = arguments[ i ] || {};
		i++;
	}
 
	// 判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值空对象
	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
	 	target = {};
	}
 
	// 若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
	// 则目标参数即为jQuery本身,而target表示的参数不再为目标参数
	// Extend jQuery itself if only one argument is passed
	if ( i === length ) {
		target = this;
		i--;
	}
	 
	// 从第i个参数开始遍历
	for ( ; i < length; i++ ) {
		// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,
		// 因此可以用null来同时过滤掉null和undefind
		// 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null ) {
	  
			// 使用for~in获取该参数中所有可枚举的属性
			// Extend the base object
			for ( name in options ) {
				src = target[ name ]; // 目标参数中name字段的值
				copy = options[ name ]; // 当前参数中name字段的值,有可能是值,Object,Array
		 
				// 若参数中属性的值就是目标参数,停止赋值,进行下一个字段的赋值
				// 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解
				// Prevent never-ending loop
				if ( target === copy ) {
				   continue;
				}
		 
				// 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值
				// Recurse if we're merging plain objects or arrays
				// jQuery.isPlainObject()返回值为Boolean类型,如果指定的参数是纯粹的对象,则返回true,否则返回false
				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
					// 若当前参数中name字段的值为Array类型
					// 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化
					if ( copyIsArray ) {
						//被复制的属性的值类型为Array
					   copyIsArray = false;
					   //判断该字段在target对象是否存在,存在且为Array,则直接使用原对象,否则创建空的Array
					   clone = src && jQuery.isArray(src) ? src : [];
					 
					}else{
						// 被复制的属性的值得类型为Object
					   //判断该字段在target对象是否存在,若存在且为Object则直接使用,否则创建空的Object
					   clone = src && jQuery.isPlainObject(src) ? src : {};
					}
		 
					// 递归处理,此处为2.2
					// Never move original objects, clone them  
					target[ name ] = jQuery.extend( deep, clone, copy );
		 
					// deep为false,则表示浅度拷贝,直接进行赋值
				// Don't bring in undefined values
				}else if ( copy !== undefined ) {			
					// 若copy是简单的类型且存在值,则直接进行赋值
				    // 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
				    target[ name ] = copy;
				}
		    }
	 	}
	}
	 
	// 返回修改后的目标参数
	// Return the modified object
	return target;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值