深、浅拷贝之间的关系

深、浅拷贝之间的关系

什么是赋值

赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分

  • 基本数据类型:赋值,赋值之后两个变量互不影响
  • 引用数据类型:赋,两个变量具有相同的引用,指向同一个对象,相互之间有影响
//所以赋值操作是直接把一个变量交给另一个变量
const a = 1;
const b = a;//这里赋值是将栈内存的值直接给新变量
const x = {name: '111'};
const y = x;//这里赋值,赋的是引用对象的地址栈的值存的是堆内存的地址

什么是浅拷贝

可以简单理解为新创建一个变量用来拷贝目标变量,并且只解决第一层问题,如果浅拷贝是基本类型数据,直接赋值,如果是引用类型数据,则对其第一层进行赋值操作,即拷贝第一层的基本类型值,以及第一层的引用类型地址

如何实现

  • Object.assign()

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

let a = {
    name: "zw",
    book: {
        title: "You Don't Know JS",
        price: "45"
    }
}
let b = Object.assign({}, a);
console.log(b);
// {
// 	name: "zw",
// 	book: {title: "You Don't Know JS", price: "45"}
// } 

a.name = "change";//这里只改变了a变量栈内存中的值,不会影响b变量
a.book.price = "55";//这里则直接改了两个变量中共同指向的book的堆内存地址中的值
console.log(a);
// {
// 	name: "change",
// 	book: {title: "You Don't Know JS", price: "55"}
// } 

console.log(b);
// {
// 	name: "zw",
// 	book: {title: "You Don't Know JS", price: "55"}
// } 

  • 扩展运算符Spread
let b = {...a};//对a进行扩展,并放入新的对象中,效果域asign一样
  • Array.prototype.slice()

slice() 方法返回一个新的数组对象,这一对象是一个由 beginend(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。

// 木易杨
let a = [0, "1", [2, 3]];
let b = a.slice(1);
console.log(b);
// ["1", [2, 3]]

a[1] = "99";
a[2][0] = 4;//要牢记,浅拷贝只赋值第一层,如果第一层有引用类型数据,则它的改变会导致原对象中该值的改变
console.log(a);
// [0, "99", [4, 3]]

console.log(b);
//  ["1", [4, 3]]

什么是深拷贝

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

实现深拷贝的方法:

1.递归实现深拷贝:

    <script>
        let obj = {
            name: 'zw',
            number: [10, 20],
            fn: function () {
                console.log(123);
            },
            old: {
                one: '1',
                two: "2"
            }
        }
        // 说明一个函数
        function copy(obj) {
            var newobj = null;
            //通过typeof判断是否为引用数据类型且不等于null
            //如果等于null直接返回newobj
            if (typeof (obj) === 'object' && obj !== null) {
                newobj = obj instanceof Array ? [] : {}//这里创建一个新的引用数据类型用以合并和存放解析后的数据
                //newobj = obj.isArray(obj)?[]:{};
                for (const key in obj) {
                    newobj[key] = copy(obj[key])//递归实现对每一个引用数据类型解析并赋值给一个新创建的引用数据类型
                }
            }
            else {
                newobj = obj;//当解析到基本数据类型时即可以直接赋值。
            }
            return newobj;
        }
        let a = new copy(obj)
        a.number[0] = 555
        console.log(obj);
        console.log(a);
    </script>

核心思想:引用数据类型是有基本数据类型构成的,并且,基本数据类型是不存在深浅拷贝这一说的,那么我们只需要将引用数据类型的每一层次的基本数据类型赋值,并遍历到最深处的基本数据并赋值就可以完成深拷贝。

2.通过JSON的方法

const a = JSON.parse(JSON.stringify(数据))
//JSON.stringify(需要拷贝数据)转化为JSON字符串
//JSON.parse(JSON字符串) 将JSON数据格式的字符串转化为对象
### 拷贝与浅拷贝的区别及用法 #### 基本概念 在编程领域,特别是面向对象的语言中,拷贝和浅拷贝是两种不同的数据结构复制方法。它们的主要差异在于如何处理嵌套的对象或引用类型的变量。 - **浅拷贝**是指创建一个新的对象,这个新对象会存储原对象中非引用类型字段的值以及引用类型字段的引用地址[^1]。这意味着如果修改了被引用的内容,则会影响原始对象和其他通过该引用访问到的对象。 - **拷贝**则是指完全克隆整个对象及其内部所有的子对象副本,使得源对象与其副本之间没有任何关联关系[^5]。因此,在执行任何一方上的更改都不会反映到另一方上。 #### 实现方式 ##### Java 中的例子: ###### 浅拷贝示例: ```java public class ShallowCopyExample implements Cloneable { int value; String text; public Object clone() throws CloneNotSupportedException { return super.clone(); // 默认实现的是浅拷贝 } @Override public String toString() { return "ShallowCopyExample{" + "value=" + value + ", text='" + text + '\'' + '}'; } } ``` 上述代码展示了如何利用 `clone()` 方法来完成一个类实例的浅拷贝操作。需要注意的是,默认情况下,`Object` 类提供的 `clone()` 函数只会做一层级别的复制——即只复制当前层面上的数据成员而不会入递归地去复制那些可能存在的复杂结构内的其他对象实例[^2]。 ###### 拷贝示例: 为了达成真正的拷贝效果,通常有两种途径可选:一是手动编写构造函数或者工厂模式来进行逐项赋值;二是借助序列化机制自动完成这一过程。 以下是基于序列化的解决方案之一: ```java import java.io.*; public class DeepCopyExample implements Serializable, Cloneable { private transient static final long serialVersionUID = 1L; int number; AnotherClass anotherObj; protected DeepCopyExample deepClone() throws IOException, ClassNotFoundException{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (DeepCopyExample)ois.readObject(); } } class AnotherClass implements Serializable{} ``` 这里采用了Java内置的标准库功能实现了完整的拷贝逻辑。通过先将目标对象写入字节流再读取出来的方式,能够有效规避掉单纯调用 `super.clone()` 所带来的局限性问题。 #### 应用场景 - 当只需要简单地共享某些部分而不希望改变原有状态时可以选择采用浅拷贝策略; - 如果确实存在多层级依赖关系并且要求绝对隔离的话则应该考虑运用拷贝技术[^3]。 #### 优缺点分析 | 特性 | 浅拷贝 | 拷贝 | |------------|-------------------------------------|----------------------------------| | 复制速度 | 较快 | 相对较慢 | | 内存占用量 | 少 | 更大 | | 数据独立性 | 不够理想 | 高度独立 | 综上所述,开发者应根据实际需求权衡选用合适的拷贝形式以达到最佳性能表现的同时满足业务逻辑的要求[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值