在JS中对于普通的json, 可用如下方式进行简单的深度拷贝
1 2 let json = { a : "aa" };let newJson = JSON .parse (JSON .stringify (json));
不过当json中包含一些JS中的对象及函数的时候, 用这样的方法会使数据丢失, 并且这个无法解决循环引用的问题, 所谓循环引用指的是
1 2 3 4 5 6 7 let b={};let a={ b :b }; b.a =a; console .log (a);
这时JSON.stringify(a)
就出现了异常
由于存在这些问题, 所以就编写了一个拷贝函数, 来做这件事情, 代码实现如下
实现代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function copyObject (o ) { let objectMap = new WeakMap (); function copy (object ) { if (objectMap.get (object)) { return objectMap.get (object); } if (typeof object !== "object" ) { return object; } if (object instanceof RegExp ) { return object; } let newObject = new object.constructor ( ); objectMap.set (object, newObject); for (let k in object) { newObject[k] = copy (object[k]); } return newObject; } return copy (o); }
代码中通过let objectMap = new WeakMap();
保存拷贝过的对象, 解决循环引用的问题
通过递归拷贝其中的对象, 若是基本类型、正则对象或函数则直接返回
测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class ObjA { constructor (v ) { this .a = v; } print ( ) { console .log (this .a || "!!!" ); } } function ObjB (v ) { this .name let a = v; this .print = () => { console .log (a || "!!!" ); } } let objA = new ObjA (666 );let objB = new ObjB (777 );let json0 = {};let json1 = { a : () => 'aaa' , b : [123 , "abc" , /abcd/ ], c : { d : function ( ) { return "ddd" }, e : [123 , 2 , 3 ], f : objA, g : objB }, r : json0 } json0.r = json1; let json2 = copyObject (json1);json2.c .e [1 ] = "asdasd" ; json2.r .r .r .r .b [1 ] = "rrrr" ; console .log (json1);console .log (json2); json2.c .f .print (); objA.a = 888 ; objA.print (); json2.c .f .print (); json2.c .g .print ();
经过测试, 以上场景的输出均与预计相同