小白:手写深拷贝的学习过程

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解决。具体解决见文章里所说。
小白:手写深拷贝的学习过程_第1张图片

另外还学习到了如何拷贝函数、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判断可以通过,从而设置了环引用的值。
小白:手写深拷贝的学习过程_第2张图片
图一
小白:手写深拷贝的学习过程_第3张图片
图二
小白:手写深拷贝的学习过程_第4张图片
图三
小白:手写深拷贝的学习过程_第5张图片
图四

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/false
set.size
set.clear()

9、如何拷贝函数?
思路:函数toString,使用正则找到函数体和参数,返回new Function(参数,函数体)

10、如何拷贝RegExp?
这个没看懂,等后面看懂了补充把
小白:手写深拷贝的学习过程_第6张图片

你可能感兴趣的