对象的浅克隆和深克隆

277 阅读2分钟

介绍几种深拷贝的方法

1.概念

  1. 深拷贝和浅拷贝是只针对Object和Array这样的复杂类型的
  2. javascript中存储对象都是存地址的,所以浅拷贝是都指向同一块内存区块,而深拷贝则是另外开辟了一块区域。
  3. 浅拷贝,也就是说a和b指向了同一块内存,所以修改其中任意的值,另一个值都会随之变化
  4. 深拷贝,也就是说a和b指向不同的内存,所以修改其中任意的值,另一个值不会随之变化

2.数据类型

  1. 基本数据类型:number,string,boolean,null,undefined五类;存放在栈(stack)。
  2. 引用数据类型(Object类)有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等;存放在堆(heap)。

3. 方法

1. 浅拷贝-解构

var o1 = {a: 1, b: 2, c: {cc: 1}}
var o2 = o1
var o = {...o1}

var a1 = [1,2,3]
var a2 = [4,5,6]
var a = [...a1, ...a2]

2. 浅拷贝-直接赋值

var o1 = {a: 1}
var o = o1
var a1 = [1,2,3]
var a = a1

3. 浅拷贝-数组的方法

let a=[0,1,[2,3],4],
let a2 = a.slice();
let a3 = a.concat();
let a1 = a // 情况2
let a4 = [...a]  // 情况1

4. 浅拷贝-Object.assign()

Objcet.assign({}, obj) 浅拷贝 属性是有限制的,只拷贝源对象的自身属性,不拷贝继承属性,也不拷贝不可枚举的属性(enumerable: false),也不能拷贝get set属性

可枚举性(enumerable)用来控制所描述的属性,是否将被包括在for...in循环之中。具体来说,如果一个属性的enumerable为false,下面三个操作不会取到该属性。 Object.defineProperty(o, 'b', {value: 2, enumerable: false})

let o1 = {a: 1, b: {bb: 2}}
let o2 = {c: 1, d: {dd: 2}}
const o = Object.assign({}, o1, o2);

5. 深拷贝-JSON.parse(JSON.stringify(obj))

var o1 = {
    a: undefined,
    b: function(){console.log('11')}, 
    c: /[1-9]/, 
    d: new Date(), 
    e: NaN, 
    f: Infinity, 
    g: -Infinity,
    h: null
}
const o1 = JSON.parse(JSON.stringify(o1));

但是会出现以下情况

  • undefined、函数 丢了;
  • null,Infinity,-Infinity,NaN变成null;
  • 正则变成{};
  • new Date() 由对象变成字符串; 原型链没了;
  • 对象就是object,所属的类没了

6. 深克隆-jq的方法, $.extend(true, [], arr)

let a=[0,1,[2,3],4],
b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

7. 深拷贝-递归

function deepCopy(o) {
    if (o instanceof Array) {
        var n = [];
    	for (var i = 0; i < o.length; ++i) {
    	    n[i] = deepCopy(o[i]);
    	}
        return n;
    } else if (o instanceof Function) {
    	var n = new Function("return " + o.toString())();
    	return n
    } else if (o instanceof Object) {
    	var n = {}
    	for (var i in o) {
       	    n[i] = deepCopy(o[i]);
    	}
    	return n;
    } else {
        return o;
    }
}

8. 深拷贝-MessageChannel-用于两个页面之间的传值

let obj = {
    a: 1,
    b: {
        c: 2,
        d: 3
    },
    f: undefined,
    fun: function () {
        console.log('fun')
    }
}

function deepCopy (obj) {
    return new Promise((resolve) => {
        const { port1, port2 } = new MessageChannel()
        port2.onmessage = ev => resolve(ev.data)
        port1.postMessage(obj)
    })
}

deepCopy(obj).then((copy) => { // 请记住`MessageChannel`是异步的这个前提!
    let copyObj = copy
    copyObj.b.c = null
    console.log(copyObj, obj)
    console.log(copyObj == obj)
})