JavaScript中深拷贝和浅拷贝

1、数据类型

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。

基本数据类型的特点:直接存储在栈(stack)中的数据

引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

2、深浅拷贝的区别

深浅拷贝主要区别在复杂数据类型,对于基本数据类型,没有区别,改变拷贝的数据,都不会改变原数据

浅拷贝(shallow copy):

浅拷贝只拷贝引用(地址值),当拷贝的新对象发生改变时,原对象也会发生相同的改变,也就是说,浅拷贝会影响原来的元素

深拷贝(deep copy):

每一级的数据都会拷贝,拷贝后,两个对象拥有不同的地址,当拷贝出来的对象发生改变时,原对象内容不会改变,两者互不影响

3、实现浅拷贝

(1)、直接赋值法:

var arr = [1,2,3]
var newarr = arr;
newarr[1] = 5;
console.log(arr,newarr);//[1, 5, 3],[1, 5, 3]

(2)、Object.assign()

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

<script>
  // 1.Object.assign()
  var obj = {
  name: "jack",
  age: 18,
  person: {
    name: "tim",
    age: 28,
  },
};
//将{}和obj合并,返回一个新的obj对象
var objNew = Object.assign({}, obj);
objNew.name = "tom";//当object只有一层的时候,是深拷贝
objNew.person.name = "Diana";//当object只有一层的时候,是浅拷贝
console.log(obj, "obj");
console.log(objNew, "objNew");
</script>

(3)、Array.prototype.concat()

数组concat方法 用途: 合并2个或多个数组,返回一个浅拷贝对象

<script>
  //3、Array.prototype.concat()
  var arr2 = [1, "hello", { usename: "tom" }];
var arr3 = arr2.concat();
arr2[2].usename = "tim";
console.log(arr2[2].usename, "arr2"); //tim
console.log(arr3[2].usename, "arr3"); //tim
</script>

(4)Array.prototype.slice()

slice(start, end); start为起始元素位置,end为截止元素位置,

var arr4 = [1, "hello", { usename: "tom" }];
var arr5 = arr4.slice();
arr4[2].usename = "diana";
//console.log(arr4[2].usename, "arr4"); //diana
//console.log(arr5[2].usename, "arr5"); //diana

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。

对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

4、实现深拷贝

(1)、Object.assign()

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

<script>
  //1、Object.assign();
  var obj = {
  //当object只有一层的时候,是深拷贝
  name: "jack",
  age: 18,
};
var objNew = Object.assign({}, obj);
objNew.name = "tom";
console.log(obj.name, "obj"); //jack
console.log(objNew.name, "objNew"); //tom
</script>

(2)、JSON.parse(JSON.stringify())

原理:用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝

注意:这种方法虽然可以实现数组或对象深拷贝,但不能处理函数

<script>
  var arr1 = [
  1,
  "hello",
  { usename: "tom" },
  function () {
    console.log(111);
  },
];
var arr2 = JSON.parse(JSON.stringify(arr1));
arr1[2].usename = "diana";
console.log(arr1[2].usename); //diana
console.log(arr2[2].usename); //tom
console.log(arr2[3]);//null
</script>

(3)、手写递归方法

原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝

<script>
  function deepClone(oldData) {
    // 1、判断oldData的数据类型
    if (typeof oldData == "object" && oldData !== null) {
      // 3、再判断类型是否是数组,根据类型返回[],{},开辟新的空间,放深拷贝数据
      var res = Array.isArray(oldData) ? [] : {};
      // 4、遍历数据,拿到属性,将属性值赋值给拷贝的数据
      for (var k in oldData) {
        // 5、判断这个k属性是否是oldData上自有的属性,原型链上的就不算了
        if (oldData.hasOwnProperty(k)) {
          // 6、对象有可能是嵌套对象,所以,需要递归再进行判断,一层层,直到拷贝了所有的数据
          res[k] = deepClone(oldData[k]);
        }
      }
      return res;
    } else {
      // 2、如果不是对象或数组,则返回原数据
      return oldData;
    }
  }

//  测试:
let obj = {
  name: "jack",
  age: 18,
  hobby: ["song", "run"],
  sayHi(msg) {
    console.log(msg);
  },
};
let newObj = deepClone(obj);
// obj.sayHi("hi");
// newObj.sayHi("hello");
newObj.name = "tom";
newObj.hobby = ["唱歌", "跑步"];
console.log(obj, "obj");
console.log(newObj, "newObj");
</script>

(4)、通过jQuery的extend方法实现深拷贝

var array = [1,2,3,4];
        var newArray = $.extend(true,[],array);

(5)、lodash函数库实现深拷贝

lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值