jQuery中的extend的用法及实现对象和数组的深浅合并和深浅克隆

jQuery中的extend方法的作用

  • 1.给jQuery的原型和对象扩展方法
  • 2.数组和对象的深浅合并
jQuery.extend = jQuery.fn.extend = function () {
		var options, name, src, copy, copyIsArray, clone,
			target = arguments[0] || {},
			i = 1,
			length = arguments.length,
			deep = false;

		// Handle a deep copy situation
		if (typeof target === "boolean") {
			deep = target;

			// Skip the boolean and the target
			target = arguments[i] || {};
			i++;
		}

		// Handle case when target is a string or something (possible in deep copy)
		if (typeof target !== "object" && !isFunction(target)) {
			target = {};
		}

		// Extend jQuery itself if only one argument is passed
		if (i === length) {
			target = this;
			i--;
		}
		
		for (; i < length; i++) {

			// Only deal with non-null/undefined values
			if ((options = arguments[i]) != null) {

				// Extend the base object
				for (name in options) {
					copy = options[name];

					// Prevent Object.prototype pollution
					// Prevent never-ending loop
					if (name === "__proto__" || target === copy) {
						continue;
					}

					// Recurse if we're merging plain objects or arrays
					if (deep && copy && (jQuery.isPlainObject(copy) ||
							(copyIsArray = Array.isArray(copy)))) {
						src = target[name];

						// Ensure proper type for the source value
						if (copyIsArray && !Array.isArray(src)) {
							clone = [];
						} else if (!copyIsArray && !jQuery.isPlainObject(src)) {
							clone = {};
						} else {
							clone = src;
						}
						copyIsArray = false;

						// Never move original objects, clone them
						target[name] = jQuery.extend(deep, clone, copy);

						// Don't bring in undefined values
					} else if (copy !== undefined) {
						target[name] = copy;
					}
				}
			}
		}

		// Return the modified object
		return target;
	};

jQuery源码中extend方法jQuery.extend = jQuery.fn.extend = function () {};是这么定义的,jQuery对象和jQuery的实例对象都可以直接调用。根据传入的参数不同,实现的功能不同:
1.向jQuery的对象或原型上扩展方法:
$.extend(function(){}); 是向JQ对象上扩展方法,一般扩展的都是工具类的方法。
$.fn.extend(function(){});是向JQ原型上扩展方法,这些方法都是供实例调用的,一般用来添加一些jQuery插件。

  • 浅合并:$.extend(obj1,obj2);

obj2替换obj1,最后返回的是obj1,类似于:Object.assign。
特点:如果obj1和obj2中存在相同属性名的引用数据类型值,obj2中的属性值会直接覆盖obj1中的值;

//浅合并 isPlainObjecteach都是用的jQuery源码中工具方法
 var shallowMerge = function shallowMerge(obj1, obj2) {
        var isPlain1 = isPlainObject(obj1),
            isPlain2 = isPlainObject(obj2);
        //判断obj1 和obj2 是否为纯粹的对象,哪个是返回那个
        if (!isPlain1) return obj2;
        if (!isPlain2) return obj1;
        each(obj2, function (key, value) {
        //遍历obj2中的每一项替换obj1中属性名相同的值
            obj1[key] = value;
        });
        return obj1;
    };
  • 深合并:$.extend(true,obj1,obj2);

obj2替换obj1,最后返回的是obj1。
特点:
obj1/obj2都是对象:迭代obj2,依次替换obj1;
obj1不是对象,obj2是对象:obj2替换obj1;
obj1是对象,obj2不是对象:依然以obj1的值为主;
obj1/obj2都不是对象:obj2替换obj1

var deepMerge = function deepMerge(obj1, obj2, cache) {
        // 防止对象的循环嵌套导致的死递归问题
        //如果cache不是一个数组返回一个空数组
        cache = !Array.isArray(cache) ? [] : cache;
        //判cache中是否存在obj2 如果存在直接返回obj2(说明obj2这个对象是类似嵌套对象let obj2={};obj2.obj2=obj2)
        if (cache.indexOf(obj2) >= 0) return obj2;
        //将要合并的对象先存到cache中
        cache.push(obj2);

        // 正常处理
        var isPlain1 = isPlainObject(obj1),
            isPlain2 = isPlainObject(obj2);
        //只要它俩有一个不是对象,走浅合并的逻辑,不存在引用数据类型值覆盖的问题,如果这俩都不是对象,直接obj2覆盖obj1的值返回即可。
        if (!isPlain1 || !isPlain2) return shallowMerge(obj1, obj2);
        each(obj2, function (key, value) {
        	//递归调用,多传递cache参数
            obj1[key] = deepMerge(obj1[key], value, cache);
        });
        return obj1;
    };
  • 浅克隆

特点:对于引用数据类型的值,克隆出来的对象和原对象用的还是一个堆地址。如果操作某一个值两个对象获取到的值都是改变后的。
实现浅克隆的方法有很多:
let obj = {x:100,y:{name:“XXX”,age:18}};
let obj2 = Object.assign({},obj);
在这里插入图片描述

let obj = {x:100,y:{name:“XXX”,age:18}};
let obj2 = {…obj};
在这里插入图片描述


 	/*
     * 对象或者数组的浅克隆 
     */
    var shallowClone = function shallowClone(obj) {
        var type = toType(obj),
            Ctor = null;
        // 其他特殊值的处理
        if (obj == null) return obj;
        //获取obj的构造函数 如果是正则或date类型new一个新的
        Ctor = obj.constructor;
        if (/^(regexp|date)$/i.test(type)) return new Ctor(obj);
        //symbol和bigint类型返回Object(obj)
        if (/^(symbol|bigint)$/i.test(type)) return Object(obj);
        //error类型需要特殊处理,new Error(obj.message)
        if (/^error$/i.test(type)) return new Ctor(obj.message);
        //函数类型给它包一层
        if (/^function$/i.test(type)) {
            return function anonymous() {
                return obj.apply(this, arguments);
            };
        }
        // 数组和纯粹对象,我们基于循环的方案来处理
        if (isPlainObject(obj) || type === "array") {
            var result = new Ctor();
            each(obj, function (key, value) {
                result[key] = value;
            });
            return result;
        }
        return obj;
    };
     
  • 深克隆

特点:克隆出来的对象和原对象完全没关系,不存在引用数据类型指向相同的堆地址。对象中的某个属性值改变时,不会影响其它对象中的属性值。

/*
     * 对象或者数组的浅克隆 
     */
    var deepClone = function deepClone(obj, cache) {
        var type = toType(obj),
            Ctor = null,
            result = null;
        //如果不是对象或者不是数组  浅克隆
        if (!isPlainObject(obj) && type !== "array") return shallowClone(obj);
        // 防止死递归
        //如果cache不是一个数组返回一个空数组
        cache = !Array.isArray(cache) ? [] : cache;
        //判cache中是否存在obj 如果存在直接返回obj(说明obj这个对象是类似嵌套对象let obj={};obj.obj=obj)
        if (cache.indexOf(obj) >= 0) return obj;
        cache.push(obj);
        // 正常的迭代处理
        Ctor = obj.constructor;
        //获取到obj的构造函数 创造一个新的实例
        result = new Ctor();
        each(obj, function (key, value) {
        	//递归调用,直到不存在引用数据类型值为止。
            result[key] = deepClone(value, cache);
        });
        return result;
    };

ps:以上代码中涉及到的isPlainObject()、each()、toType()函数均使用的是jQuery源码(二)中的工具类方法。
jQuery源码分析(二)之数据类型检测:https://blog.csdn.net/Lele___/article/details/111588761

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值