js基础-8-浅拷贝和深拷贝

一,浅拷贝

需要明确的一点是:只有引用数据类型才讨论深浅拷贝,基本数据类型本身存的是值,拷贝会直接开辟新的空间来存值,不存在相互影响。
拷贝的是对象的属性,一个改变,相互影响

			var obj1={
    
    
				name:'zhangsan',
				arr:[1,2,3,4]
			}
			function copy(val){
    
    
				var obj2={
    
    }
				for (var stl in val){
    
    
					obj2[stl]=val[stl]   //将val对象中的属性,一一赋值给obj2
					//因为对象的第二个属性是数组(非基本数据类型,拷贝的是地址!)
				}
				return obj2
			}
			var obj2=copy(obj1)
			obj1.name="libai"   //它是基本数据类型,不存在深浅拷贝问题,都是深拷贝,拷贝的是值,不会互相影响
			obj1.arr[0]="修改"   //修改了其中一个,互相影响,都改变了,这就是浅拷贝
			console.log(obj1)
			console.log(obj2)

在这里插入图片描述
在这里插入图片描述

二,深拷贝

拷贝源对象,一个改变,互相不影响。
对于深拷贝而言,实际上需要讨论的是几层深拷贝。
1,对于对象的一层拷贝 ,有一个方法

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

于是对象的一层深拷贝写法:

			var obj1={
    
    
				name:"beijing",
				arr:[1,2,3,4]
			}
			var obj2=Object.assign({
    
    },obj1)   //将obj1中的可枚举属性复制一份,放到obj2中
			obj1.name="shanghai"
			obj1.arr[0]="更改"
			console.log(obj1)  
			console.log(obj2)

在这里插入图片描述
2,对于数组的一层拷贝

arr.slice(start,end):方法可从已有数组中返回选定的元素,返回一个新数组,包含从start到end(不包含该元素)的数组元素。如果不给参数,则是全部复制
var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice();
console.log(arr1); //[1, 2, [3, 4]]
console.log(arr2); //[1, 2, [3, 4]]
arr2[2][1] = 5; 
console.log(arr1); //[1, 2, [3, 5]]
console.log(arr2); //[1, 2, [3, 5]]     都改变了,所以它也只能实现一层深拷贝

3,实现深拷贝的常用方式:

JSON.parse(JSON.stringify(obj))   //先把对象转化为json,再转化返回一个新的对象
var obj1 = {
    
    
    x: 1, 
    y: {
    
    
        m: 1
    }
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 2}}
这种方法不能深拷贝含有undefined、function、symbol值的对象(会直接忽略这些东西),不过 JSON.parse(JSON.stringify(obj)) 简单粗暴,已经满足 90% 的使用场景了。

4,利用递归实现深拷贝

Object.keys(obj)
对象.keys(传入源数组或者源对象)
返回值是一个数组,里面的元素是源数组的索引或者源对象的键值。
function deepCopy(obj) {
    
    
    // 创建一个新对象
    let result = {
    
    }
    let keys = Object.keys(obj),    //获取传入对象/数组的键/索引构成的数组
        key = null,
        temp = null;
    for (let i = 0; i < keys.length; i++) {
    
    
        key = keys[i];       //依次取得对应的键/索引
        temp = obj[key];     //依次取得元素/属性
        // 如果元素/属性的值又是一个对象或者数组则递归操作
        if (temp && typeof temp === 'object') {
    
       //因为typeof检测[],{}和null都会返回object,所以这里用temp&&来规避null
            result[key] = deepCopy(temp);//递归操作
        } else {
    
    
        // 否则直接赋值给新对象
            result[key] = temp;
        }
    }
    return result;
}
var obj1 = {
    
    
    x: {
    
    
        m: 1
    },
    y: undefined,
    z: function add(z1, z2) {
    
    
        return z1 + z2
    },
    a: Symbol("foo")
};
var obj2 = deepCopy(obj1);
obj2.x.m = 2;
console.log(obj1); //{x: {m: 1}, y: undefined, z: ƒ, a: Symbol(foo)}
console.log(obj2); //{x: {m: 2}, y: undefined, z: ƒ, a: Symbol(foo)}

这种方法,可以全部深度拷贝。且适用于数组和对象。

猜你喜欢

转载自blog.csdn.net/weixin_42349568/article/details/108989148