视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JavaScript深层克隆对象
2020-11-27 20:24:40 责编:小采
文档

今天做题看到了深层克隆对象,并且要求在原型链上编程

于是心血来潮索性来复习一下这个知识点


克隆对象,这名词看着高大上,其实也没什么,就是拷贝一个长的一模一样的对象
也许有初学的小伙伴在想,那还不简单么,so easy

var obj1 = {name: 'payen'};var obj2 = obj1;

这可并不是克隆对象,obj1和obj2根本就是同一个对象,
他俩指向同一个内存地址空间
就好比它们拿到了同样的一个小房子
这是因为对象是引用值(堆数据)
说到引用值
JavaScript中引用值只有对象
这里注意,数组是特殊的对象,函数也是特殊的可执行对象,
也就是说,它们也是对象
所谓深层克隆对象就是说复制一份一模一样的小房子
不知道我这么说大家能不能理解= ̄ω ̄=
也就是深层克隆对象引用值需要拷贝,而相对的浅层克隆对象只要把那个引用值拿过来就好了
不明白不要紧,看完代码就理解了

浅层克隆对象

首先来一起看看浅层克隆对象吧

var house = {
 name: 'payen',
 people: {
 father: true,
 mother: true
 }
}function easyClone(obj){
 var newObj = {}; for(var prop in obj){ if(obj.hasOwnProperty(prop)){
 newObj[prop] = obj[prop];
 }
 } return newObj;
}var newHouse = easyClone(house);

不要吐槽我用easy,一时想不起来“浅”英文咋说来着(真不知道我英语六级怎么过的)
关于那个for-in有一个小性能问题,感兴趣的童鞋可以看看我的另一篇文章
传送门o( ̄▽ ̄)d
这段代码很简单我就不多解释了
来看看chrome控制台

看样子很棒的样子
那么我现在做一件事
给新房子加一个人

看来这个”新房子”并不新啊,不要被变量名字迷惑了
所以,有引用值出现,浅层克隆并不好用了

深层克隆对象

既然如此,我们怎么办呢
既然要得到新的对象,我们创建一个新对象,把旧对象内部的东西,再拷贝到新对象不就得了
还有一个问题如果对象里还有对象呢
那么就继续重复创建添加的过程,很显然是一个循环的过程
不过循环有两种

  • 迭代

  • 递归

  • 毫无疑问递归更胜一筹
    在递归循环中,遇到满足终止条件的条件时逐层返回来结束
    那么我们就可以通过递归逐层查找引用值,直到没有引用值为止
    还是看代码吧

    var house = {
     name: 'payen',
     people: {
     father: true,
     mother: true,
     child: {
     age: 1
     }
     },
     money: [1000,2000,3000]
    }function deepClone(original, target){
     var target = target || {};// 如果target为undefined或没传参,设置空对象
     for(var prop in original){// 遍历原对象
     if(original.hasOwnProperty(prop)){// 只拷贝对象内部,不考虑原型链
     if(typeof original[prop] === 'object'){// 引用值
     if(Object.prototype.toString.call(original[prop]) === '[object Array]'){
     target[prop] = [];// 处理数组引用值
     }else{
     target[prop] = {};// 处理对象引用值
     }// 可以用三目运算符
     deepClone(original[prop],target[prop]);// 递归克隆
     }else{// 基本值
     target[prop] = original[prop];
     } 
     }
     } return target;
    }var newHouse = deepClone(house);

    上面写了那个if-else挺适合用三目运算符的,不过我感觉太冗长了,强迫症表示看了很不舒服
    为了证明它真的深层克隆了,我特意把原始房子变复杂了
    (我们不考虑函数的深层克隆,麻烦并且意义不大)
    这回它真的是新房子了

    我就不展开了
    可以看出来在新对象的引用值改动,旧对象并没有变
    下面我同样实现了原型链上深层克隆对象
    道理是一样的

    var house = {
     name: 'payen',
     people: {
     father: true,
     mother: true,
     child: {
     age: 1
     }
     },
     money: [1000,2000,3000]
    }Object.prototype.cloneTo = function(obj){
     var obj = obj || {}; 
     for(var prop in this){ 
     if(this.hasOwnProperty(prop)){ 
     if(typeof this[prop] === 'object'){ 
     if(Object.prototype.toString.call(this[prop]) === '[object Array]'){
     obj[prop] = [];
     }else{
     obj[prop] = {};
     } 
     this[prop].cloneTo(obj[prop]);
     }else{
     obj[prop] = this[prop];
     }
     }
     } return obj;
    }var newHouse = {};
    house.cloneTo(newHouse);

    下载本文
    显示全文
    专题