JS - 手写深拷贝、浅拷贝

目录

深拷贝

解释        

手写实现

测试用例

浅拷贝

解释        

手写实现

其它注意事项

深拷贝

解释        

        深拷贝是一种复制对象的方法,它会创建一个新的对象,与原始对象完全独立,并且递归地将原始对象的所有属性进行复制。

        即如果原始对象包含其他对象或引用类型的属性,深拷贝将递归复制它们,因此在新对象中,新的复合对象将具有原始对象所有属性的副本。因此,原始对象和新对象的修改不会相互影响

手写实现

1. 通过 lodash 的  cloneDeep()  也可以直接调用实现;

2. 通过  JSON.parse(JSON.stringify(...))  序列化实现,缺点:数据丢失;

  • ① 不能拷贝函数
  • ② 不能拷贝  Symbol() 
  • ③ 不能拷贝循环引用的对象(会报错,比如  window.window.window.window 
  • ④ key 的值为  undefined  不会拷贝

3. 手写递归判断

// 手写实现
function deepClone(obj) {
    // 基本类型 或 空
    if (typeof obj !== 'object' || obj === null) {
        return obj;
    }

    // 引用类型
    let newObj = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        // 只复制自身属性,忽略原型链上的可遍历属性
        if (obj.hasOwnProperty(key)) {
            // 基本类型 或 空
            if (typeof obj[key] !== 'object' || obj[key] === null) {
                newObj[key] = obj[key];
            } 
            // 引用类型
            else {
                newObj[key] = deepClone(obj[key]);
            }
        }
    }
    return newObj;
}

测试用例

const obj1 = {
  name: 'Tom',
  age: 20,
  hobbies: ['reading', 'music', 'sports'],
  address: {
    city: 'Beijing',
    district: 'Haidian'
  }
};

const obj2 = deepClone(obj1);
obj2.hobbies.push('travel');
obj2.address.city = 'Shanghai';

console.log(obj1); // {name: 'Tom', age: 20, hobbies: ['reading', 'music', 'sports'], address: {city: 'Beijing', district: 'Haidian'}}
console.log(obj2); // {name: 'Tom', age: 20, hobbies: ['reading', 'music', 'sports', 'travel'], address: {city: 'Shanghai', district: 'Haidian'}}

浅拷贝

解释        

        浅拷贝指的是创建一个新对象,这个对象具有原始对象属性值的副本。如果属性是原始值类型,则拷贝的是值的副本;如果属性是引用类型,则拷贝的是内存地址的副本。

        也就是说,新对象和原始对象的这个属性指向同一个内存地址(复制指针)。因此,原始对象和新对象的修改会相互影响

        可以看成最外层是深拷贝的,而遇到深层便浅拷贝了。

手写实现

// 浅拷贝有很多方法
// 1. 使用 Object.assign()
const obj2 = Object.assign({}, obj1)

// 2. 使用展开运算符
const obj3 = {...obj1}

// 3. 针对数组可使用不带参数的 Array.prototype.slice 或 Array.prototype.concat
const arr3 = arr1.slice()
const arr4 = arr1.concat()

// 4. 手写
function myClone(obj) {
    let newObj = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

其它注意事项

  • 在 IE8 以下不支持  Array.isArray()  ,需要手写实现。
if (!Array.isArray) {
    Array.isArray = function(arguments) {
        return Object.prototype.toString.call(arguments) === '[object Array]';
    }
}
  • 为什么使用不用  instanceof  来进行判断:
    •  instanceof  是检查构造函数的  prototype  是否出现在对应实例的原型链上来实现的,也就是说如果手动更改了  __proto__  指向,也会被判定到。
    • 无法正确判断  Array.prototype  是否是数组
console.log(Array.prototype instanceof Array);
// 输出 false 实际 true

const obj = { a: 1, __proto__: Array.prototype };
console.log(obj instanceof Array);
// 输出 true 实际 false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值