Today,逛segmentfault的时候,看到有很多大神手写了深拷贝,记得也有大厂把这个当作题目,那我也来学习一下吧~
在此之前,我都是间接JSON.parse(JSON.stringfy())实现深拷贝。有时写业务时,遇到一些谬误应用深拷贝就能解决。有一段时间,我居然认为"...[]"这种就是对数组进行深拷贝了.....总之这块常识把握得不够。
开始撸码!首先理解下,浅拷贝和深拷贝的含意。
以前的认知 | 当初的认知 |
---|---|
浅拷贝是间接赋值,不仅把值赋了,援用也雷同——比方浅拷贝对象a到b,如果批改a外面的某个属性,b里对应的属性也会变更。 | 浅拷贝只能赋值最外一层,比方对象obj1={a:{a:{a:1}}},浅拷贝给obj2,批改obj1.b=2,再批改obj1.b.b=2;输入ob2为{a:{a:{a:1}},b:2}。obj2.b不是对象。 |
能够应用JSON.parse(JSON.stringfy())实现,而且根本够用写业务了呢,或者依赖lodash的_.cloneDeep()实现。 | 手写 |
没遇到转换失败的场景 | JSON.parse(JSON.stringfy())有毛病:1、undefined转换会间接隐没;2、RegExp转换后变成{};3、NaN、+-Infinity转换后变成null;4、环援用会报错:TypeError: Converting circular structure to JSON |
我跟着https://segmentfault.com/a/11...这篇文章,一起手动写了下代码。写到最初都挺好,也实现了性能。在此过程中,学到了很多常识——
1、根底类型和援用类型别离有哪些?
根底类型:String Number Boolean Undefined Null
可循环的援用类型:Array Object Map Set
不可循环的援用类型:Symbol RegExp Function
2、判断类型的办法?
Object.prototype.toString.call(x)
3、递归写法?
function digui(sum) { if(sum==0){ return 0; } return sum+digui(sum-1)}console.log(digui(6));
4、拷贝Symbol的办法?
Object(Symbol.prototype.valueOf.call(x));
5、for...in 和for...of的区别
for...in | for...of |
---|---|
举荐遍历对象——对象的键名,遍历数组——数组的索引(即键名);枚举属性,包含原型 | 举荐遍历数组——元素值;遍历对象,不蕴含可枚举属性 |
6、环援用是什么意思?如何解决它的深拷贝?
环援用就是value是变量本人,能够应用Map解决。具体解决见文章里所说。
另外还学习到了如何拷贝函数、Symbol、RegExp,Map、Set。不过,也有不了解的中央:
思考1、76行代码(见图一)是判断援用数据类型,通过输入,看进去返回的temp是origin的雷同类型的空值,比方origin是{key:origin},那temp就是{}。这时map曾经保留了key为origin,value为{}的值——这不就不对了嘛?环援用就变成了{}(见图三)。起初,我把origin只保留了一个换援用而后debugger一步步走下来,发现递归走了两次,第一次执行了map.set,走到第100行代码(见图四),把换援用作为key又循环了一次,因为第一次的map.set,所以79行代码(见图一)的if判断能够通过,从而设置了环援用的值。
图一
图二
图三
图四
7、Map如何获取值和赋值?
var map= new Map();map.get('key');map.set('key','value');
8、Set是什么?Set如何获取值和赋值?
set相似数组,但值惟一
var set = new Set()set.add(1)set.delete(2)set.has(1) ---> true/falseset.sizeset.clear()
9、如何拷贝函数?
思路:函数toString,应用正则找到函数体和参数,返回new Function(参数,函数体)
10、如何拷贝RegExp?
这个没看懂,等前面看懂了补充把