其他分享
首页 > 其他分享> > 2021.06.17(理解js中的深拷贝和浅拷贝)

2021.06.17(理解js中的深拷贝和浅拷贝)

作者:互联网

在JS当中,数据类型分为基本数据类型引用类型,其中基本数据类型(string,number,boolean,undefined,null,symnol......),引用类型为Object(Array、Object、Function......)。   内存分为栈内存堆内存,其中栈内存用来存储基本数据类型(存取速度快,存放量小)和引用类型的地址(存取速度慢,存放量大,其引用指针存于栈区,并指向引用本身),而堆内存则存储引用数据类型。  

基本数据类型:赋值,赋值之后两个变量互不影响

引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响

<script>
    // 基本类型
    var a = 100;
    var b = a;
    a = 200;
    console.log(a, b); // 200, 100 ,a b指向不同的数据

    // 引用类型指向同一份数据
    var a = { c: 1000 };
    var b = a;
    a.c = 2000;
    console.log(a.c, b.c); // 2000, 2000 全是2000,a b指向同一份数据
</script>

通常在开发中并不希望改变变量 a 之后会影响到变量 b,这时就需要用到浅拷贝和深拷贝。

浅拷贝

 

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,

所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

<script>
  function cloneShallow(source) {
    var target = {};
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
    return target;
  }
  var a1 = { b: { c: {} } };
  var a2 = cloneShallow(a1); // 浅拷贝
  a2.b.c = { d: "1" };
  console.log("a1---", a1);  //{b:{c:{d:"1"}}}
  console.log("a2---", a2);  //{b:{c:{d:"1"}}}

  var a5 = { b: { d: [1,2] } };
  var a6 = cloneShallow(a5); // 浅拷贝
  a6.b.d = [3,4];
  console.log("a5---", a5);  //{b:{d[3,4]))
  console.log("a6---", a6);  //{b:{d[3,4]))

  // 注意:当object只有一层的时候,是深拷贝,例如如下:
  var a3 = { b:'9'};
  var a4 = cloneShallow(a3);
  a4.b = '10';
  console.log("a3---", a3);  //{b:'9'}
  console.log("a4---", a4);  //{b:'10'}
</script>

Object.assign()

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

Object.assign(target, ...sources)

 

Array.prototype.concat()

 

 

Array.prototype.slice()

...obj 展开运算符

 

 

 深拷贝

 

深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响

 

<script>
  function isObject(obj) {
    return typeof obj === "object" && obj != null;
  }
  function cloneDeep(source) {
    if (!isObject(source)) return source; // 非对象返回自身

    var target = Array.isArray(source) ? [] : {};
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        if (isObject(source[key])) {
          target[key] = cloneDeep(source[key]); // 注意这里
        } else {
          target[key] = source[key];
        }
      }
    }
    return target;
  }
  var obj = {
    title: "study",
    list: ["1", "2", "3"],
  };
  var obj2 = cloneDeep(obj);
  obj2.title = "play";
  obj2.list = ["3", "4"];
  console.log("obj", obj);  //title: "style",list: ["1", "2", "3"]
  console.log("obj2", obj2);  //title: "play",list: ["3", "4"]
</script>

JSON.parse(JSON.stringify(object))

JSON.stringify():将对象转成 JSON 字符串。

JSON.parse():将字符串解析成对象。

通过 JSON.parse(JSON.stringify()) 将 JavaScript 对象转序列化(转换成 JSON 字符串),

再将其还原成 JavaScript 对象,一去一来我们就产生了一个新的对象,而且对象会开辟新的栈,从而实现深拷贝。

注意

注意,该方法的局限性:

1、不能存放函数或者 Undefined,否则会丢失函数或者 Undefined;

2、不要存放时间对象,否则会变成字符串形式;

3、不能存放 RegExp、Error 对象,否则会变成空对象;

4、不能存放 NaN、Infinity、-Infinity,否则会变成 null;

5、……更多请自行填坑,具体来说就是 JavaScript 和 JSON 存在差异,两者不兼容的就会出问题。

 

 函数库 Lodash

cloneDeep() 方法
npm i --save lodash
var _ = require('lodash');

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

 

2021-06-17  11:18:29

标签:2021.06,17,对象,source,key,var,console,拷贝
来源: https://www.cnblogs.com/zhenggc99/p/14892672.html