当前位置:首页 > 生活百科

js实现深拷贝的方法(js深拷贝和浅拷贝的区别)

栏目:生活百科日期:2025-02-03浏览:0

在实际开发当中,我们经常会遇到要对对象进行深拷贝的情况。而且深拷贝这个问题在面试过程中也经常会遇到,下面就对本人在学习过程中的收获,做以简单的总结。

什么是浅拷贝,什么是深拷贝?

什么是浅拷贝

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

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对象拥有两个基本类型的属性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 copyy.b.f === x.b.f       // truez.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 直接表示的数据结构。

自己造轮子

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

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!}());

“js实现深拷贝的方法(js深拷贝和浅拷贝的区别)” 的相关文章

发光键盘好不好(达尔优LK169发光机械键盘使用体验分享)

话说换工作以后,公司配的笔记本电脑办公,键盘实在是不好用。考虑到家里暂时没有多余的键盘,于是买个新键盘,就成了我双11的首要计划。但突然一天,看到了张大妈的推送...

中国最新科技成果,中国最新科技成果展示

刚刚,中国又一尖端科技取得重大突破!创新科技理念今天文章转载自公众号财经要参,作者要参君来源:财经要参(mofzpy)一今天,当很多国人热议保时捷女司机的时候,...

天猫店群玩法玩法介绍,实实在在可以月入10万的项目

月入10万对于淘宝、拼多多无货源来说可能有些遥远,或者说要开几十家店,但是放在天猫上来说,一家店就足够了。不信?来看数据平均每天的营业额都在1~2万之间,利润在...

在农村做什么好赚钱,农村最稀缺的行业推荐

一,“绿色肉”的饲养业如今多元化的生活已经到来,人们的消费质量也在提升,口味也在发生变化,更偏向一些绿色的肉食,以草食为主的动物肉类产品很受消费者的青睐,因为现...

dnf图表系统组建失败怎么办(教你其解决方法)

DNF(地下城与勇士)是一款很经典的老牌游戏,深受用户喜欢。但有部分用户反映,玩DNF的时候会出现提示图表系统组件失败的,那么电脑玩DNF图标系统组建失败怎么办...

回话的技巧软件(高情商回话技术)

不会说话你就输了,掌握倾听、提问、赞美的秘诀、学会逻辑思维,精准表达轻松救场。在日常生活中,说话也是一门重要的公开需要我们补习,请大家认真看我的读书心得,或许能...

女神隔离霜好用吗(100%的仙女们用了都说好)

VIpICI是韩国的彩妆大师李京民各大一线大牌明星的御用化妆师在2005年创立的品牌所以可以说个挺专业的彩妆品牌但是相信它家的那款女神隔离你们一定在朋友圈刷到过...

iphone12和iphone12pro区别尺寸(苹果12和12pro参数对比

iPhone12系列在国内高端手机市场依然有很大的市场份额,尤其是在华为手机遇到困境的情况下,大部分高端用户也流向了iphone,甚至iphone12在发布仅半...

京东母婴体验店加盟费多少(加盟京东母婴生活馆利弊和费

母婴零售进入变革深水区,一方面,母婴店数量已趋饱和,进入了加速整合的关键时期,无论是势单力薄的单体门店还是盲目进场的加盟小店,在人货场更迭的倒逼之下都迫切需要降...

goldwave消除人声教程(消除人声保留背景音乐软件推荐)

首先你需要准备一款AU软件1.导入一段音频2.在菜单栏-新建-多轨会话(快捷键:Ctrl+N)3.点击确定4.新建好的工程界面是这样的6.将音频拖动到轨道上7....