【3】前端手撕-深浅拷贝

1. 浅拷贝

对于引用数据类型只拷贝第一层,若第一层中也存在引用数据类型,则拷贝的仅仅是地址,若该数据修改,则会影响原数据

示例数据

js 复制代码
const originalObj = {
    name: 'John',
    age: 30,
    address: {
        city: 'Beijing',
        country: 'China',
    },
    hobbies: ['reading', 'traveling', 'cooking'],
};

const originalArr = [1, 2, 3, { a: 4 }];

使用Object.assign()

js 复制代码
const shallowCopyObj = Object.assign({}, originalObj);

解构赋值

js 复制代码
// 对象
const shallowCopyObj2 = { ...originalObj };
// 数组
const shallowCopyArr4 = [...originalArr];

拷贝数组

js 复制代码
// 拷贝数组:使用Array.prototype.slice()
const shallowCopyArr = originalArr.slice();

// 拷贝数组:使用Array.prototype.concat()
const shallowCopyArr2 = originalArr.concat();

// 拷贝数组:使用Array.from()
const shallowCopyArr3 = Array.from(originalArr);

2. 深拷贝

深拷贝完全复制对象,如果对象中存在嵌套的引用数据类型,则会另外开辟一个空间来进行存储,拷贝后的对象与原对象互相独立,互不影响

递归实现深拷贝

js 复制代码
function deepClone(obj) {
    // 基础数据类型直接原样返回
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    // 处理数组
    if (Array.isArray(obj)) {
        return obj.map(deepClone);
    }

    const result = {};
    Object.keys(obj).forEach((key) => {
        // 只拷贝对象自己本身的属性,不拷贝原型链上的属性
        if (obj.hasOwnProperty(key)) {
            result[key] = deepClone(obj[key]);
        }
    });

    return result;
}

递归实现深拷贝进阶版:解决循环引用,Date和正则的拷贝

js 复制代码
function deepCloneCircular(obj, visited = new WeakMap()) {
    // 基础数据类型直接原样返回
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    // 检查循环引用
    if (visited.has(obj)) {
        return visited.get(obj);
    }

    if (obj instanceof Date) {
        return new Date(obj);
    }

    if (obj instanceof RegExp) {
        return new RegExp(obj.source, obj.flags);
    }

    const result = Array.isArray(obj) ? [] : {};

    // 保存引用避免循环引用
    visited.set(obj, result);

    Object.keys(obj).forEach((key) => {
        // 只拷贝对象自己本身的属性,不拷贝原型链上的属性
        if (obj.hasOwnProperty(key)) {
            result[key] = deepCloneCircular(obj[key], visited);
        }
    });

    return result;
}

JSON方法实现深拷贝

js 复制代码
function deepCloneByJSON(obj) {
    return JSON.parse(JSON.stringify(obj));
}

局限性:

  1. 无法拷贝函数:如果对象中存在函数,拷贝结果中函数将会丢失
  2. 无法拷贝undefined:拷贝过程中值为undefined的属性会丢失
  3. 无法拷贝Symbol:拷贝过程中如果键名为Symbol也会拷贝丢失
  4. Date类型会被转为字符串
  5. 正则对象在拷贝过程中也会丢失
  6. NaNInfinity在拷贝过程中会变为null
  7. 若对象中存在循环饮用,则会报错
  8. 对于Map,Set,WeakMap,WeakSet的拷贝结果会变为{}空对象

使用现代浏览器支持方法

js 复制代码
// 现代浏览器原生支持 (Chrome 98+, Firefox 94+, Node 17+)
const result = structuredClone(originalObj);
相关推荐
yangyanping201087 分钟前
Vue入门到精通八之data 函数
javascript·vue.js·ecmascript
XW01059998 分钟前
5-8能被3,5和7整除的数的个数(用集合实现)
前端·javascript·数据结构·数据库·python·for循环
历程里程碑11 分钟前
37 线程安全单例模式深度解析
java·服务器·开发语言·前端·javascript·c++·排序算法
wuhen_n12 分钟前
v-once和v-memo完全指南:告别不必要的渲染,让应用飞起来
前端·javascript·vue.js
喵叔哟24 分钟前
10. 【Blazor全栈开发实战指南】--JavaScript调用Blazor
开发语言·javascript·windows·udp
云浪27 分钟前
5 分钟入门 fetch
前端·javascript
晓得迷路了33 分钟前
栗子前端技术周刊第 120 期 - Vite 8.0、Solid v2.0.0 Beta、TypeScript 6.0 RC...
前端·javascript·vite
optimistic_chen38 分钟前
【Vue入门】组件及组件化
前端·javascript·vue.js·html·组件
下雨打伞干嘛1 小时前
手写Promise
开发语言·前端·javascript
还是大剑师兰特1 小时前
50个 filter相关的公共函数
开发语言·javascript·ecmascript