温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JavaScript怎么实现深拷贝

发布时间:2022-01-26 15:31:18 来源:亿速云 阅读:618 作者:iii 栏目:开发技术

本篇内容主要讲解“JavaScript怎么实现深拷贝”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript怎么实现深拷贝”吧!

什么是浅拷贝

关于浅拷贝的概念,我在网上看到一种说法,直接上代码。

var person = {name: "Jason", age: 18, car: {brand: "Ferrari", type: "430"}}; var person1 = person;       //他们认为这是浅拷贝

但是我个人认为,上面这个根本不涉及拷贝,只是一个简单的引用赋值。以我的理解,浅拷贝应该是不考虑对象的引用类型的属性,只对当前对象的所有成员进行拷贝,代码如下:

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

上面这段代码中,person对象拥有两个基本类型的属性nameage,一个引用类型的属性car,当使用如上方法进行拷贝的时候,nameage属性会被正常的拷贝,但是car属性,只会进行引用的拷贝,这样会导致拷贝出来的对象personCopyperson会共用一个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全局对象的parsestringify方法来实现深复制也算是一个简单讨巧的方法。

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

然而使用这种方法会有一些隐藏的坑,它能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。

自己造轮子

下面我们给出一个简单的解决方案,当然这个方案是参考别人的方式来实现的。希望对大家有用。

var clone = (function() {     //这个方法用来获取对象的类型 返回值为字符串类型 "Object RegExp Date Array..."     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) {             var flags = '';             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];                     }                 }             }             return newArr;         },         //正常对象的处理 第二个参数为是否做浅拷贝         'Object': function(obj, shallow) {             var newObj = {}, prop, handler;             for (prop in 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;         var handler = 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("I'm not dead yet!");     // Output:     // true     // true     // true     // I'm not dead yet! }());

到此,相信大家对“JavaScript怎么实现深拷贝”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI