美文网首页
JS 深浅拷贝

JS 深浅拷贝

作者: lazy_tomato | 来源:发表于2020-09-20 17:46 被阅读0次

START

  • 番茄我又又又来写点啥啦。
  • 最近敲代码,总是遇到需要修改数据,在前端展示。但是最后并不想修改原数据的情况。所以,需要涉及到数据的拷贝了,数据拷贝又分深拷贝,浅拷贝。所以写一篇文章记录一下。
  • 本文仅个人的想法,能力有限,参考即可,后续对这个有更深入的理解了,再补充。
  • 啰嗦一句,深拷贝浅拷贝 和 深克隆浅克隆,其实都差不多一个意思啦,看个人习惯如何称呼。

JS 的数据类型

在说深浅克隆之前,我想提一下JS的数据类型。

  • JS数据类型,可以大致分为两种:基本数据类型引用数据类型

  • 基本数据类型:

  1. Undefined
  2. Null
  3. Boolean
  4. Number
  5. String
  • 引用数据类型:
  1. object
  • 当然 ES6 引入了一种新的数据类型 Symbol (这里暂时不讨论 Symbol)

为什么要这样区分数据类型呢?

  • 因为基本数据类型数据,保存在栈内存
  • 引用类型保存在堆内存中

那么为什么要分两种保存方式呢?

  • 根本原因是在于保存在栈内存的必须是大小固定的数据,引用的类型的大小不固定,只能保存在堆内存中。但是我们可以将引用类型的地址存储在栈内存中。
  • 文字不好理解的话,举个例子:

    // 1.定义一个基本数据类型--数字类型的变量
    var a = 1
    
    // 定义一个引用类型的变量
    var obj = {
        name: "lazy_tomato"
    }
    
  • 上面代码执行后,在内存中其实就是这样的。

    堆栈内存说明.png

知道js变量的保存方式有什么用呢?

  • 看一看简单的题目就知道了。

题目一

var a = 1

var b = a

console.log('变量a为:', a, "变量b为:", b);  //变量a为: 1 变量b为: 1

a = 88

console.log('变量a为:', a, "变量b为:", b);   //变量a为: 88 变量b为: 1

题目二

var a = {
    name: '张三',
    age: 14
}

var b = a

console.log('变量a为:', a, "变量b为:", b);  
//变量a为: { name: '张三', age: 14 } 变量b为: { name: '张三', age: 14 }

a.name = 'lazy_tomato'

console.log('变量a为:', a, "变量b为:", b);   
//变量a为: { name: 'lazy_tomato', age: 14 } 变量b为: { name: 'lazy_tomato', age: 14 }
  • 题目一中,为什么我修改a,不会修改b ?

  • 题目二中,为什么我修改a,会同时修改b ?

    正是因为题目二中,我们 var b = a 做的操作就是:

    声明一个变量b,b栈内存中存储的地址,和a一样,都指向

    {
    name: '张三',
    age: 14
    }

    所以 a.name = 'lazy_tomato' 执行后 a指向堆内存中为:

    {
    name: 'lazy_tomato',
    age: 14
    }

    但是 b栈内存中存储的地址也指向这个对象,所以 修改a,会同时修改b

浅拷贝

  • 浅拷贝: 创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

  • 看不懂定义?那就简单点说: 就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。

  • 题目二,其实就是属于浅拷贝,修改了变量a,变量b也跟着改变。

浅拷贝实现方式

  1. 可以通过简单的赋值实现

    类似上面的例子

  2. 利用 Object.assign()实现

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

var obj = { a: { a: "hello", b: 21 } };

var newObj = Object.assign({}, obj);

console.log("obj变量为:", obj, "newObj: ", newObj)
//obj变量为: { a: { a: 'hello', b: 21 } } newObj:  { a: { a: 'hello', b: 21 } }

newObj.a.a = "lazy_tomato";

console.log("obj变量为:", obj, "newObj: ", newObj)
//obj变量为: { a: { a: 'lazy_tomato', b: 21 } } newObj:  { a: { a: 'lazy_tomato', b: 21 } }

注意:当object只有一层的时候,是深拷贝,例如如下:

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);

console.log(obj1, obj2); 
//{ a: 10, b: 20, c: 30 } { a: 10, b: 20, c: 30 }

obj1.b = 100;
console.log(obj1, obj2); 
//{ a: 10, b: 100, c: 30 } { a: 10, b: 20, c: 30 }

深拷贝

  • 深拷贝: 将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

深拷贝实现方式

1、对象只有一层的话可以使用上面的:Object.assign()函数
2、转成 JSON 再转回来
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1, obj2)  //{ body: { a: 10 } } { body: { a: 10 } }
obj1.body.a = 20;
console.log(obj1, obj2) //{ body: { a: 20 } } { body: { a: 10 } }

缺点

  • 拷贝对象的值,如果存在函数、undefined、symbol,在经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失;
  • 没办法拷贝不可枚举的属性,也不像for in 那样可以拷贝原型上的数据;
  • 拷贝Date引用类型会变成字符串
  • 拷贝RegExp 、Error 引用类型会变成 空对象
  • 对象中含有NaN,Infinity和-Infinity,则序列化的结果会变成null
3、递归拷贝
  • 写个函数实现递归拷贝
function deepClone(initalObj, finalObj) {    
    var obj = finalObj || {};    
    for (var i in initalObj) {        
      var prop = initalObj[i];        
      if(prop === obj) {            
        continue;
      }        
      if (typeof prop === 'object') {
        obj[i] = (prop.constructor === Array) ? [] : {};            
        arguments.callee(prop, obj[i]);
      } else {
        obj[i] = prop;
      }
    }    
    return obj;
  }

参考的相关网站博客

END

  • 写着写着,发现自己还有好多不懂的呀,o(╥﹏╥)o,挂出的相关博客都很棒,推荐看看。加油啦~~ 后续对js更加精通了,再来补充这篇文章。
  • 个人记录,参考即可。

相关文章

  • JS文集的目录

    js基础心法 深浅拷贝(递归)深浅拷贝(首层浅拷贝) js 数据处理 数组对象查找的常见操作数组对象去重的常见操作...

  • js的深浅拷贝

    js的深浅拷贝可以分为数组的深浅拷贝和对象的深浅拷贝 一、数组的深浅拷贝如果只是简单的将数组中的元素付给另外一个数...

  • js深浅拷贝

    项目中,一般会用loadsh库,地址:https://github.com/lodash/lodash 浅拷贝方法...

  • js 深浅拷贝

    浅拷贝 是 把对象或者数组的第一层 key 或者 索引 赋到 新的 对象或者对象上 深拷贝是迭代浅拷贝的操作,也就...

  • js 深浅拷贝

    深拷贝 更好的写法: 浅拷贝 浅拷贝,还可以用 Object.assign 、展开运算符 ...

  • JS深浅拷贝

  • JS深浅拷贝

    JS存储方式 JS中存在基本数据类型和引用数据类型1.基本数据类型:number,string,boolean,n...

  • JS深浅拷贝

    浅拷贝 浅拷贝的意思就是只复制引用,而未复制真正的值。 深拷贝 深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制...

  • JS 深浅拷贝

    START 番茄我又又又来写点啥啦。 最近敲代码,总是遇到需要修改数据,在前端展示。但是最后并不想修改原数据的情况...

  • JS 深浅拷贝

    https://blog.csdn.net/flyingpig2016/article/details/52895620

网友评论

      本文标题:JS 深浅拷贝

      本文链接:https://www.haomeiwen.com/subject/uzrpyktx.html