跟着月影学Javascript之深浅拷贝| 青训营笔记

79 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

Javascript的深浅拷贝

什么是拷贝?

首先在Javascript语言中,对数据分成了七种:

Number,String,undefined,null,Bool,Symbol和Object。

我们将上面这些数据在造出一份一模一样数据的过程就叫拷贝。

数据在内存中是如何存储的?

我们再把上面的七种简单分成两大类,基础数据类型(前六种)和复杂数据类型(Object)。

我们区分深浅拷贝其实对数据在内存中的不同存储方式,在内存中我们分为两种存储方式,栈存储和堆存储。

对于基础数据类型:是直接存储在栈中,而对于复杂数据类型:它的指针存在栈中,而实际数据存在堆中,使用时用栈的指针去找到堆中的数据。

image

深拷贝和浅拷贝的区别?

首先我们的深浅拷贝之分是只对于Object的,在其它基础数据类型两种拷贝都一样。

浅拷贝:只是把指针复制一份去指原指针指向的数据,并没有真正复制了数据、

深拷贝:不仅复印了指针,同时在堆中也拷贝了一份。

浅拷贝实现:

  • Object.assign()
  • Array.protopyte.concat() // concat方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组, 用在这里相当于整个用一个空数组合来合并
  • Array.protopyte.slice() // slice()方法用于提取目标数组的一部分,返回一个新数组,用在这里相当于整个数组都提取
let obj = {
  a:{
    name: 'lyy',
    age: 18,
  },
}

let arr = [1,3,{
  name: 'lyy'
}];

let cloneobj = Object.assign(obj);
console.log(cloneobj)

let colnearr = arr.concat();
console.log(colnearr)

let colnearr = arr.slice();
console.log(colnearr)

深拷贝实现:

  • JSON.parse(JSON.stringify())
  • 手动实现深搜/广搜

JSON.parse(JSON.stringify())

通过把整个对象用JSON.stringify转成JSON字符串,如何在用JSON.parse()拼装成对象,这一来一回就在堆中创造了新的空间。 但是这个做法无法处理对象中有function。

let arr = [1,3,{
  name: 'lyy'
}];
let colnearr = JSON.parse(JSON.stringify(arr));
arr[2].name = 'LYY'
console.log(colnearr,arr)

手动实现

//深搜版
function dfs(target,hash_table = new WeakMap()) {
    if (typeof target === 'Object') {
    let clone = Array.isArray(target) ? [] : {};
        if (hash_table.get(target)) return hash_table.get(target);
        hash_table.set(target,clone);
        for (const key in target) {
            clone[key] = dfs(target[key])
        }
        return clone
    } else {
        return target
    }
}
//广搜版
function bfs(target,hash_table = new WeakMap())  {
    if(typeof target !== 'Object') return target
    let q = [];
    q.push(target);

    while (q.length) {
        let u = q.shift(); 
        let clone;
        if (hash_table.get(u)) {
            clone = hash_table.get(u);
        } else {
            clone = Array.isArray(u) ? [] : {};
            hash_table.set(u,clone);
        }

        for (const key in u) {
            let t = u[key];
            if(typeof t !== 'Object') {
	            clone[key] = t
            }
            if (!hash_table.get(t)) {
                clone[key] = Array.isArray(t) ? [] : {};
                hash_table.set(t,clone);
                q.push(t);
            }
        }
    }
    return hash_table.get(target)
}
const target = {
    field1: 1,
    field2: undefined,
    field3: {
        child: 'child'
    },
    field4: [2, 4, 8]
};
target.target = target
console.log(dfs(target),bfs(target))

赋值和浅拷贝的区别是什么?

赋值和浅拷贝之间是有区别的,这个区别只在复杂数据类型时会有

赋值:赋值操作只会对对象的指针进行一个复制,复制的新指针和原指针指向的是同一块内存。

浅拷贝:浅拷贝会先创建一个空的新对象,接着遍历目标对象的每个数据,如果是基础数据类型,则会复制一份放在新对象中,如果是复杂数据类型则只会拷贝指针。