A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 逆风TO 黑马粉丝团   /  2020-5-4 15:42  /  7377 人查看  /  170 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 逆风TO 于 2020-5-4 15:47 编辑

什么是克隆

其实js里的克隆跟生活里说的克隆是一样的。有一个本体,克隆出跟本体一摸一样的副体,当本体“受伤”时副体是不会“受伤”的,js的克隆也是如此。
来看下面代码

[JavaScript] 纯文本查看 复制代码
<script>
      var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
      };
      console.log(
        `本体有---${benti.top}、${benti.leg}、${benti.waist}、${benti.hand}`
      );
</script>
想要克隆出一个副体应该怎么做呢?有些人就想到直接将本体赋值给副体
[JavaScript] 纯文本查看 复制代码
<script>
      var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
      };
      var futi = benti;   
      console.log(
        `本体有---${benti.top}、${benti.leg}、${benti.waist}、${benti.hand}`
      );
      console.log(
        `副体有---${futi.top}、${futi.leg}、${futi.waist}、${futi.hand}`
      );
 </script>

输出结果

从输出结果来看确实是“克隆”出来一个副体,上面说过克隆出来的副体是不会因为本体“受伤”而“受伤”的,那再看下面代码
[JavaScript] 纯文本查看 复制代码
<script>
      var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
      };
      var futi = benti;
      benti.top = "本体的铁头受伤了"; //本体的头受伤了
      console.log(
        `本体有${benti.top}、${benti.leg}、${benti.waist}、${benti.hand}`
      );
      console.log(
        `副体有${futi.top}、${futi.leg}、${futi.waist}、${futi.hand}`
      );
    </script>

输出结果

按道理来说本体受伤,副体不应该受伤的呀!为什么会这样呢?因为在内存中,对象存储是存在一个地址中的,这样直接赋值给副体,相当于直接把地址值给了副本,并不是克隆一个新的地址值,看下图

所以说这样子的做法并不是克隆。接下来我们要谈谈浅克隆和深克隆

浅克隆
什么是浅克隆
只克隆第一级属性,如果某个属性又是一个内嵌的子对象,不会进入子对象中克隆子对象的内容。

这里用for in 来实现浅克隆,看以下代码
[JavaScript] 纯文本查看 复制代码
<script>
      var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
      };
      //浅克隆
      function clone(oldObj) {
        var newObj = {};
        for (var key in oldObj) {
          newObj[key] = oldObj[key];
        }
        return newObj;
      }
      var futi = clone(benti);
      benti.top = "本体的铁头受伤了"; //本体的头受伤了
      console.log(
        `本体有---${benti.top}、${benti.leg}、${benti.waist}、${benti.hand}`
      );
      console.log(
        `副体有---${futi.top}、${futi.leg}、${futi.waist}、${futi.hand}`
      );
</script>
输出结果

克隆出来的副体与本体没有联系,即使改变本体的属性值,副体也不会被被改变这就是浅克隆,看下图的解释

这样就达到了基本的浅克隆,但是这个浅克隆有些小问题需要注意,如果有些人想向克隆函数传一个null,数字,字符串,数组呢?不能都返回一个对象给别人吧!我们是想别人想克隆什么类型的就返回什么类型的给别人。那可以改一改上面的代码
[Java] 纯文本查看 复制代码
<script>
      var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
      };
      //浅克隆
      function clone(oldObj) {
        //如果传进来的参数是null,那就返回一个null
        if (oldObj == null) {
          return null; //直接退出
        }
        //如果传进来的是原始类型值,就返回原始类型值
        if (typeof oldObj != "object") {
          return oldObj; //直接退出
        } else {
          var newObj = Array.isArray(oldObj) ? [] : {}; //不要直接创建对象,先使用三目运算符判断是创建数组还是对象
          for (var key in oldObj) {
            newObj[key] = oldObj[key];
          }
          return newObj; //返回新对象或数组
        }
      }
      //克隆一个对象
      var futi = clone(benti);
      benti.top = "本体的铁头受伤了"; //本体的头受伤了
      console.log(
        `本体有---${benti.top}、${benti.leg}、${benti.waist}、${benti.hand}`
      );
      console.log(
        `副体有---${futi.top}、${futi.leg}、${futi.waist}、${futi.hand}`
      );

      //参数为null
      var boor = clone(null);
      console.log(boor);

      //参数为数字,字符串
      var number = clone(12);
      var string = clone("string");
      console.log(number);
      console.log(string);

      //参数为数组
      var arr = clone([1, 2, 3, 4, 5]);
      console.log(arr);
    </script>

输出结果

这样浅克隆就实现了。接下来看看什么是深克隆吧,深克隆跟浅克隆有什么区别呢?

深克隆什么是深克隆

既可以克隆第一级属性,如果某个属性又是一个内嵌的子对象,深克隆会进入子对象中,继续克隆内嵌子对象及其内容。

什么是内嵌的子对象呢?看下面的代码

[Java] 纯文本查看 复制代码
var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
        chuanzhe:{
			yifu:"adds",
			xiezi:"AJ",
			kuzi:"boshilong"
		}
};

对象benti中的chuanzhe就是内嵌的子对象,如果用浅克隆的方式克隆出来的副体是有问题的,因为对象存储是存在一个地址中,所以浅克隆是无法克隆内嵌的子对象,那深克隆是怎么实现的呢?是利用递归的思想来解决这个问题的,
看下面的代码

[Java] 纯文本查看 复制代码
<script>
      var benti = {
        top: "铁头",
        leg: "大长腿",
        waist: "细腰",
        hand: "小手",
        chuanzhe: {
          yifu: "adds",
          xiezi: "AJ",
          kuzi: "boshilong",
        },
      };
      //深克隆
      function clone(oldObj) {
        //如果传进来的参数是null,那就返回一个null
        if (oldObj == null) {
          return null; //直接退出
        }
        //如果传进来的是原始类型值,就返回原始类型值
        if (typeof oldObj != "object") {
          return oldObj; //直接退出
        } else {
          var newObj = Array.isArray(oldObj) ? [] : {}; //不要直接创建对象,先使用三目运算符判断是创建数组还是对象
          for (var key in oldObj) {
            newObj[key] = clone(oldObj[key]); //如果属性有内嵌子对象就再次调用克隆函数   递归的思想
          }
          return newObj; //返回新对象或数组
        }
      }
      //克隆一个对象
      var futi = clone(benti);
      benti.top = "本体的铁头受伤了"; //本体的头受伤了
      console.log(benti);
      console.log(futi);

      //参数为null
      var boor = clone(null);
      console.log(boor);

      //参数为数字,字符串
      var number = clone(12);
      var string = clone("string");
      console.log(number);
      console.log(string);

      //参数为数组
      var arr = clone([1, 2, 3, 4, 5]);
      console.log(arr);
    </script>

输出结果

这样就实现了深克隆了,最主要的还是这句代码newObj[key] = clone(oldObj[key]);利用了递归的思想,这里就不做过多的介绍了。浅克隆和深克隆就介绍到这里啦!说得不好的,请多多指教。

转自CSDN



170 个回复

倒序浏览
感谢分析,
回复 使用道具 举报
小公举 来自手机 中级黑马 2020-5-18 14:44:04
藤椅
克隆看着还挺难的,加油吧,谢谢楼主分享
回复 使用道具 举报
回复 使用道具 举报
66666666666666
回复 使用道具 举报
66666666666666666
回复 使用道具 举报
66666666666666666666
回复 使用道具 举报
66666666666666666
回复 使用道具 举报
666666666666666666666666666666
回复 使用道具 举报
我爱我1022 来自手机 中级黑马 2020-5-18 15:34:48
10#
回复 使用道具 举报
你只管去努力,剩下的交给天意
回复 使用道具 举报
加油                           
回复 使用道具 举报
我爱我1022 来自手机 中级黑马 2020-5-18 15:52:23
13#
回复 使用道具 举报
6666666666666666666
回复 使用道具 举报
你只管去努力,剩下的交给天意。
回复 使用道具 举报
感谢分享!
回复 使用道具 举报
加油加油加油!!!
回复 使用道具 举报
6666666666666666666666666
回复 使用道具 举报
666666666666666666
回复 使用道具 举报
66666666666666666666666666666666
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马