【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. NaN和Infinity在拷贝过程中会变为null
  7. 若对象中存在循环饮用,则会报错
  8. 对于Map,Set,WeakMap,WeakSet的拷贝结果会变为{}空对象

使用现代浏览器支持方法

js 复制代码
// 现代浏览器原生支持 (Chrome 98+, Firefox 94+, Node 17+)
const result = structuredClone(originalObj);
相关推荐
jktantan1 小时前
Vue keep-alive 切标签后滚动位置回顶?因为 onDeactivated 里读到的 scrollTop 是 0
前端·javascript·vue.js
总要学点什么2 小时前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
前端精髓3 小时前
调用openrouter的免费API模型
java·前端·javascript
螺丝钉tina9 小时前
[Playwright] [02]常用命令与调试:Debug UI、Mode和 Trace Viewer
开发语言·javascript·测试工具·ui·自动化
开开心心就好10 小时前
竖式除法出题工具,整除余数混合模式
运维·服务器·前端·javascript·ocr·perl·1024程序员节
এ慕ོ冬℘゜10 小时前
JS 事件循环、宏任务微任务:单线程底层原理 + 执行顺序
开发语言·javascript·ecmascript
web打印社区10 小时前
Lodop排障总纲-常见报错一张表
开发语言·前端·javascript·chrome·websocket
程序员大阳10 小时前
副队长JavaScript教程(56)-DOM之表单操作
javascript·dom·表单操作
Dxy123931021611 小时前
JS AES加密详解
开发语言·javascript·ecmascript
FRing0312 小时前
JavaScript入门到精通三十三(异常处理、call方法、apply方法、bind方法、防抖、节流)
开发语言·前端·javascript