JavaScript的深拷贝实现

2023-02-05 0 1,036

在前述合作开发之中,他们时常会碰到要对第一类展开深复本的情形。所以深复本那个难题在复试操作过程中也时常会碰到,上面就对生前在自学操作过程中的斩获,Ins13zD单纯的归纳。

甚么是浅复本,甚么是深复本?

甚么是浅复本

有关浅复本的基本上概念,我在网路上看见一类讲法,间接上标识符。

var person = {name: “Jason”, age: 18, car: {brand: “Ferrari”, type: “430”}}; varperson1 = person;//她们指出这是浅复本

但我对个人指出,上面那个显然不牵涉复本,而已三个单纯的提及表达式。以我的认知,浅复本如果是不考量第一类的提及类别的特性,只对现阶段第一类的大部份核心成员展开复本,标识符如下表所示:

function copy(obj){ var objCopy = {}; for(var key in obj){ objCopy[key] = obj[key]; } returnobjCopy; }var person = {name: “Jason”, age: 18, car: {brand: “Ferrari”, type: “430”}}; var personCopy = copy(person);

上面这段标识符中,person第一类保有三个基本上类别的特性name和age,三个提及类别的特性car,当采用如上方式展开复本的这时候,name和age特性会被恒定的复本,但car特性,只会展开提及的复本,这种会引致复本出的第一类personCopy和person会相连接三个car第一类。这种是简而言之的浅复本。

甚么是深复本

深复本的是在复本的这时候,须要将现阶段要复本的第一类内的大部份提及类别的特性展开完备的复本,也是说复本出的第一类和原第一类间没任何人统计数据是共享资源的,大部份的小东西都是她们独享的这份。

如何同时实现深复本

同时实现深复本须要考量的难题

同时实现深复本须要考量如下表所示几个因素:

传入的第一类是采用第一类字面量{}创建的第一类还是由构造函数生成的第一类如果第一类是由构造函数创建出的,那么是否要复本原型链上的特性如果要复本原型链上的特性,那么如果原型链上存在多个同名的特性,保留哪个处理循环提及的难题

第三方库同时实现深复本

jQuery的$.extend()

他们可以通过$.extend()方式来完成深复制。值得庆幸的是,他们在jQuery中可以通过添加三个参数来同时实现递归extend。调用$.extend(true, {}, …)就可以同时实现深复制,参考上面的例子:

var x = { a: 1, b: { f: { g: 1 } }, c: [ 1, 2, 3 ] }; var y = $.extend({}, x), //shallow copy z = $.extend(true, {}, x); //deep copy y.b.f === x.b.f // true z.b.f === x.b.f // false

但jQuery的那个$.extend()方式,有弊端,甚么弊端呢?他们看上面的例子:

var objA = {}; var objB = {}; objA.b = objB; objB.a = objA; $.extend(true,{},a); //那个这时候就出现异常了 //Uncaught RangeError: Maximum call stack size exceeded(…)

也是说,jQuery中的$.extend()并没处理循环提及的难题。

使用JSON第一类同时实现深复本

采用JSON全局第一类的parse和stringify方式来同时实现深复制也算是三个单纯讨巧的方式。

function jsonClone(obj) { return JSON.parse(JSON.stringify(obj)); } var clone = jsonClone({ a:1 });

然而采用这种方式会有一些隐藏的坑,它能正确处理的第一类只有 Number, String, Boolean, Array, 扁平第一类,即那些能够被 json 间接表示的统计数据结构。

她们造轮子

上面他们给出三个单纯的解决方案,当然那个方案是参考别人的方式来同时实现的。希望对大家有用。

varclone = (function() { var classof = function(o) { if(o ===null) { return “null”; } if (o === undefined) { return “undefined”; } // 这里的Object.prototype.toString很可能用的是Object.prototype.constructor.name // 这里采用Object.prototype.toString来生成类别字符串 var className = Object.prototype.toString.call(o).slice(8, -1); return className; }; //这里那个变量他们用来存储已经保存过的特性,目的在于处理循环提及的难题 var references = null; //碰到不同类别的第一类的处理方式 var handlers = { //正则表达式的处理 RegExp: function(reg) { varflags = ; flags += reg.global ?g : ; flags += reg.multiline ? m : ; flags += reg.ignoreCase ? i : ; return new RegExp(reg.source, flags); }, //时间第一类处理 Date: function(date) { return new Date(+date); }, //数组处理 第二个参数为是否做浅复本 Array: function(arr, shallow) { var newArr = [], i; for (i = 0; i < arr.length; i++) { if(shallow) { newArr[i] = arr[i]; }else { //这里他们通过reference数组来处理循环提及难题 if(references.indexOf(arr[i]) !==-1) { continue; } var handler = handlers[classof(arr[i])]; if(handler) { references.push(arr[i]); newArr[i] = handler(arr[i],false); } else { newArr[i] = arr[i]; } } } returnnewArr; },//恒定第一类的处理 第二个参数为是否做浅复本 Object: function(obj, shallow) { var newObj = {}, prop, handler; for(propin obj) { //有关原型中特性的处理太过复杂,他们这里暂时不做处理 //所以只对第一类本身的特性做复本 if (obj.hasOwnProperty(prop)) { if(shallow) { newObj[prop] = obj[prop]; }else { //这里还是处理循环提及的难题 if (references.indexOf(obj[prop]) !== -1) { continue; } handler = handlers[classof(obj[prop])]; //如果没对应的处理方式,那么就间接复制 if(handler) { references.push(obj[prop]); newObj[prop] = handler(obj[prop],false); } else{ newObj[prop] = obj[prop]; } } } }return newObj; } }; return function(obj, shallow) { //首先重置他们用来处理循环引用的那个变量 references = []; //他们默认处理为浅复本 shallow = shallow === undefined ? true : false; varhandler = handlers[classof(obj)];return handler ? handler(obj, shallow) : obj; }; }()); (function() { //上面是一些测试标识符 var date = new Date(); var reg = /hello word/gi; var obj = { prop: this ia a string, arr: [1, 2, 3], o: { wow: aha } }; var refer1 = { arr: [1, 2, 3] }; var refer2 = { refer: refer1 }; refer1.refer = refer2;var cloneDate = clone(date, false); var cloneReg = clone(reg, false); var cloneObj = clone(obj, false); alert((date !== cloneDate) && (date.valueOf() === cloneDate.valueOf())); alert((cloneReg !== reg) && (reg.toString() === cloneReg.toString())); alert((obj !== cloneObj) && (obj.arr !== cloneObj.arr) && (obj.o !== cloneObj.o) && (JSON.stringify(obj) === JSON.stringify(cloneObj))); clone(refer2,false); alert(“Im not dead yet!”); // Output: // true // true // true // Im not dead yet! }());

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务