c++ 合并string_extend、深浅合并、深浅克隆 | 继续扩展utils.js | 跟着jQuery大佬学编程思想...

▲ 点击上方蓝字关注我 ▲

文 / 景朝霞

来源公号 / 朝霞的光影笔记

ID / zhaoxiajingjing

目录:0 / extend的应用1 / 简单实现extend方法2 / 应用:深浅比较的对象合并3 / 对象的深浅合并(1)浅合并 shallowMerge(2)深合并 deepMerge(3)优化深合并4 / 深浅克隆(1)浅克隆 shallowClone(2)深克隆 deepClone5 / JQ中的extend源码

0 / extend的应用

extend 给JQ的原型和对象扩展方法

$.extend({xxx:function....}) 向JQ对象上扩展方法【工具类的方法=>用于完善类库】

$.fn.extend({xxx:function.....}) 向JQ的原型上扩展方法【供实例调用=>JQ插件】

 $.extend({     MySay:function(){         // 这里的THIS --> jQuery         console.log('miao~');     } }); $.MySay();  $.fn.extend({     MyEat:function(){         // 这里的THIS --> JQ的实例对象         console.log('炸鸡~');     } }); $('body').MyEat();

△ extend应用

1 / 简单实现extend方法

extend 方法做的事情:

把对象上的属性一一的追加到jQuery对象,或者jQuery.fn上,即:追加到this上

 jQuery.extend = jQuery.fn.extend = function (obj) {     // 容错     if (obj == null || typeof obj !== 'object') throw new TypeError('obj must be an object!');      var self = this,         keys = Object.keys(obj);      typeof Symbol !== 'undefined' ? keys = keys.concat(Object.getOwnPropertySymbols(obj)) : null;      keys.forEach(function (key) {         self[key] = obj[key];     });      return self; };

△ 最简版的extend的实现

扩展方法,就是对象的合并

但,jQuery还提供了:深比较or浅比较的合并

2 / 应用:深浅比较的对象合并

JQ的extend另一个点:基于浅比较or深比较,来实现对象的合并

$.extend(obj1, obj2) 浅合并:obj2替换obj1,最后返回的是obj1,类似于之前说的Object.assign的功能

$.extend(true, obj1, obj2) 深合并:obj2替换obj1,最后返回的是obj1

 let obj1 = {     name:'朝霞的光影笔记',     friends:{         0:'小汤圆'     } };  let obj2 = {     name:'公众号:朝霞的光影笔记',     friends:{         1:'江小虾'     },     id:'zhaoxiajingjing' }; console.log(Object.assign(obj1, obj2));

△ 需要合并的参数

e42b625eb9bf558dfbfb94dbbf625e05.png

△ 图1_Object.assign的浅合并

aa355c76678f9ea0e96f04faaafb761a.png

△ 图2_JQ中的深浅比较,合并对象

好啦,咱之前写过的那个方法库utils.js

那咱就继续往上面扩展:深浅合并、深浅克隆吧~

3 / 对象的深浅合并

深浅合并:主要是针对对象数据类型值和其他数据类型值

(1)浅合并 shallowMerge

对象的浅合并,合并规律:

A:obj1,B:obj2

① A不是对象,B是对象:B替换A

② A不是对象,B不是对象:B替换A

③ A是对象,B不是对象:依旧A为主

④ A是对象,B是对象:迭代B,替换A

 var shallowMerge = function shallowMerge(obj1, obj2) {     var isPlain1 = isPlainObject(obj1),         isPlain2 = isPlainObject(obj2);      // A不是对象,B是或者不是对象:都以B为主     if(!isPlain1) return obj2;      // A是对象,B不是对象:以A为主     if(!isPlain2) return obj1;      // A/B是对象:迭代B,替换A     each(obj2, function(key, value){         obj1[key] = value;     });      return obj1; };

△ 请自行写到utils.js里面~浅合并

(2)深合并 deepMerge

对象的深合并,合并规律:

A:obj1,B:obj2

① A和B只要有一个不是对象,那么就是浅合并

② A和B都是对象

=> 循环B时,A和B中的某个属性又是对象,那么需要递归合并

 var deepMerge = function deepMerge(obj1, obj2) {     var isPlain1 = isPlainObject(obj1),         isPlain2 = isPlainObject(obj2);      // A、B只要有一个不是对象,就浅合并     if (!isPlain1 || !isPlain2) return shallowMerge(obj1, obj2);      // A和B都是对象     each(obj2, function (key, value) {         obj1[key] = deepMerge(obj1[key], value);     });      return obj1; };

△ 深合并

(3)优化深合并

如果出现循环引用的情况,深合并怎么处理呢?

 let obj1 = {     name: '朝霞的光影笔记',     friends: {         0: '小汤圆'     } }; obj1.A = obj1; //=>【循环引用】  let obj2 = {     name: '公众号:朝霞的光影笔记',     friends: {         1: '江小虾'     },     id: 'zhaoxiajingjing' }; obj2.A = obj2; //=>【循环引用】

△ 需要合并的数据

深度合并:标记,只要处理过的,就不再处理了

 var deepMerge = function deepMerge(obj1, obj2, cache) {     // 容错:防止循环引用导致了死递归问题     cache = !Array.isArray(cache) ? [] : cache;      if (cache.indexOf(obj2) >= 0) return obj2;     cache.push(obj2);      var isPlain1 = isPlainObject(obj1),         isPlain2 = isPlainObject(obj2);      // A、B只要有一个不是对象,就浅合并     if (!isPlain1 || !isPlain2) return shallowMerge(obj1, obj2);      // A和B都是对象     each(obj2, function (key, value) {         obj1[key] = deepMerge(obj1[key], value, cache);     });      return obj1; };

△ 循环引用

循环引用:在WEB浏览器中,window.window

d58863486841e086e6424fa44d74c49e.png

△ 图3_window的循环引用

4 / 深浅克隆

对象/数组浅克隆:

1、...

2、迭代

3、内置方法,如:slice

 let obj = {gzh:{id:'zhaoxiajingjing'}}; let obj2 = {     ...obj };  let obj3 = {}; for(let key in obj){     obj3[key] = obj[key]; }  let arr2 = [{id:'zhaoxiajingjing'}, 100].slice();

深克隆:JSON.parse(JSON.stringify(obj))变为字符串,再变为对象,内存地址会重新开辟一下。但是,转为字符串并不是所有的值都支持:

c650a3a3a7524309397149d6762b7031.png

△ 图4_JSON.parse/JSON.stringify

在我现在的项目中,由于没有这么复杂的数据,都是对象的属性值是:number/boolean/string/纯粹对象/数组这样的数据,所以直接使用的就是JSON.parse(JSON.stringify())

但是,对于更复杂的数据,还需要咱写个方法好好的处理

对象的属性值可以是任意类型的值,那么,深浅克隆,就是对JS数据类型值的克隆

(1)浅克隆 shallowClone

 let obj = {     a:1,     str:'miao~',     b:true,     c:null,     0:undefined,     f:function(){},     e:/^\d+$/,     d:new Date(),     s:Symbol() }; obj.A = obj;  let arr = [10,[2], {id:'zhaoxiajingjing'}];

浅克隆:

1、 基本数据类型值

① string、number、boolean、null、undefeind 直接返回就可以了

② symbol和bigint 不能通过new的方式创建实例对象,但是可以Object(xxx)来返回对应的数据类型

2、引用数据类型值

① 函数数据类型值:直接返回一个匿名函数过去,然后在这个匿名函数中调用之前的那个函数,并指定this和传递参数

② 对象数据类型值,常见的有:

=> 日期对象、正则对象:直接再new一个新的返回就可以

=> error对象:直接new一个新的,并把错误信息传过去

=> 纯粹对象(原型链直接指向Object基类)、数组对象:new一个新的实例,再循环遍历去赋值

 var shallowClone = function shallowClone(obj) {     var type = toType(obj),         Ctor = null;      // null、undefined 直接返回     if (obj == null) return obj;      // symbol\bigint     if (/^(symbol|bigint)$/i.test(type)) return Object(obj);      // 函数数据类型     if (/^function$/i.test(type)) {         return function anonymous() {             return obj.apply(this, arguments);         };     }      Ctor = obj.constructor;      // 日期对象、正则对象     if (/^(date|regexp)$/i.test(type)) return new Ctor(obj);      // error 对象     if (/^error$/i.test(type)) return new Ctor(obj.message);      // 纯粹对象和数组:循环解决     if (isPlainObject(obj) || type === 'array') {         var restul = new Ctor();         each(obj, function (key, value) {             result[key] = value;         });          return result;     }      // 以上的都不是:① 剩下的基本数据类型值 ②……     return obj; };

△ 浅克隆

(2)深克隆 deepClone

深克隆

1、只要不是纯粹对象和数组,其他的都浅克隆即可

2、纯粹对象和数组对象:

① 他们的值有可能是以上说到的任何一种数据类型,那么需要递归深克隆

② 防止循环调用时产生死递归现象

 var deepClone = function deepClone(obj, cache) {     var type = toType(obj),         Ctor = null,         result = null;      // 不是纯粹对象和数组,都去浅克隆就行了     if (!isPlainObject(obj) || type !== 'array') return shallowClone(obj);      // 纯粹对象和数组对象      // 防止死递归     cache = Array.isArray(cache) ? cache : [];     if(cache.indexOf(obj) >= 0) return obj;     cache.push(obj);      Ctor = obj.constructor;      result = new Ctor();      each(obj, function (key, value){         result = deepClone(value, cache);     });      return result; };

5 / JQ中的extend源码

大家记得把深浅合并和深浅克隆放到utils.js里面

浅合并原则:主要针对 对象和其他数据类型值

1、A不是对象,不管B是不是对象:B替换A

2、A是对象,B不是对象:依旧是A

3、A是对象,B是对象:迭代B,替换A

深合并原则:

1、A和B只要有一个不是对象,那就是浅合并

2、A和B都是对象:

① 循环B时,需要去递归查看下A和B中的值是否也是对象

② 循环引用时,避免死递归

浅克隆原则:克隆是对 数据类型值 的克隆

1、基本数据类型值

① string\boolean\number\null\undefined,直接返回就可以了

② symbol\bigint,返回Object(xxxx)就可以了

2、引用数据类型值

① 函数数据类型值:返回一个匿名函数,在匿名函数里面去调用原来的函数,并记得修正THIS和传值

② 对象数据类型值

=> 日期对象、正则对象:new一个新的实例对象返回去就行了

=> error对象:new一个新的实例对象回去,记得传递错误的信息

=> 纯粹对象和数组对象:创建一个新的实例对象、循环遍历赋值后返回即可

深克隆原则:

1、只要不是纯粹对象和数组对象,都去浅克隆就行了

2、纯粹对象和数组对象:创建一个新的实例对象

① 循环遍历得到值时,需要递归克隆该值

② 循环引用时,需要缓存一下,不要出现死递归现象

JQ的extend方法的作用:

1、向jQuery、jQuery.fn上扩展方法:

jQuery.extend({A:function....})

jQuery.fn.extend({B:function....})

2、深浅合并:

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

深合并:$.extend(true, obj1, obj2)

下面是直接从JQ中粘贴出来的源码:

 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; };

- end -

9b7af2c08291203ff2820a284390782c.png

从"你"到"更好的你",有无限可能~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值