JavaScript 前端基础知识二:浅拷贝和深拷贝

一、前置知识详解

学习浅拷贝、深拷贝之前,需要了解的前置知识:

1.1 JavaScript数据类型

JavaScript的数据类型分为基本类型、引用类型。

  • 基本类型:Number、String、Boolean、Undefined、Null、Sysbol、BigInt
  • 引用类型:Object(对象)、Array(数组)、Function(函数)

基本类型数据保存在栈内存中。

引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中。

1.2 理解传值和传址

  • 传值:开辟新内存区域存储值

代码示例如下

let a = 3;
let b = a;
console.log(a, b); // 3 3
b = 5;
console.log(a, b); // 3 5

  • 传址:传递内存地址,而不开辟新空间

代码示例如下

let user = {
    name: 'zs',
    age: 20,
};

let user1 = user;
console.log(user, user1);
user1.name = 'lisi';
console.log(user, user1);

 

输出内容相同,因为user和user1指向了同一个内存地址。 


二、浅拷贝

2.1 浅拷贝的定义和原理

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝。 

  • 如果原始数据属性是基本类型,拷贝的就是基本类型的值。
  • 如果原始数据属性是引用类型,拷贝的就是内存地址。

浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。

2.2 实现浅拷贝的方法

2.2.1 手写递归实现

 // 方式一:手写递归实现
    function shallowClone(obj) {
        let newObj = {};
        for (let i in obj) {
            // 只要是obj的属性,直接复制一份给newObj
            if (obj.hasOwnProperty(i)) {
                newObj[i] = obj[i];
            }
        }
        return newObj;
    };
    const person = {
        name: 'zs',
        hobby: ['vball', 'tball', 'bball'],
    };
    const person1 = shallowClone(person);
    console.log('修改前打印 == ', person);
    console.log('修改前打印 == ', person1);
    person1.name = 'lisi';
    person1.hobby[0] = 'fball';
    console.log('修改后打印 == ', person);
    console.log('修改后打印 == ', person1); 

2.2.2 利用展开语法实现

 // 方式二:利用展开语法实现浅拷贝
    let obj = {
        name: 'zs',
        lessons: ['hobby', 'math', 'music'],
    };
    let hd = { ...obj };
    hd.name = 'lisi';
    hd.lessons[0] = 'english';
    console.log(obj);
    console.log(hd);

 

2.2.3 使用Object.assign实现

 // 方式三:使用Object.assign进行对象的合并
    let obj3 = {
        name: 'zs',
        lessons: ['hobby', 'math', 'music'],
    };
    let newObj3 = Object.assign({}, obj3);
    newObj3.name = 'lili'
    newObj3.lessons[0] = 'english';
    console.log(obj3);
    console.log(newObj3);

 

2.2.4 利用Array.prototype.slice实现

// 利用Array.prototype.slice实现浅拷贝
    const arr = [1, 2, { name: 'xiaoli'}];
    const newArr = arr.slice();
    newArr[2].name = 'ss';
    console.log(arr);
    console.log(newArr);

2.2.5 利用Array.prototype.contact实现

    // 方式五:利用Array.prototype.contact实现浅拷贝
    const carr = [1, 2, { name: 'xiaoli'}];
    const cnewArr = carr.slice();
    cnewArr[2].name = 'ls';
    console.log(arr);
    console.log(cnewArr);

 


三、深拷贝

3.1 深拷贝的定义和原理

 深拷贝开辟一个新的栈,两个对象属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

3.2 深拷贝的实现方法

3.2.1 手写递归实现深拷贝

// 方式一:手写递归实现深拷贝
    function deepClone(obj) {
        let newObj = obj instanceof Array ? [] : {};
        for (let i in obj) {
            if (obj.hasOwnProperty(i)) {
                if (obj[i] && typeof obj[i] == 'object') {
                    // 若对象属性还是引用类型,进行递归
                    newObj[i] = deepClone(obj[i]);
                } else {
                    // 对象属性是基本数据类型,直接赋值
                    newObj[i] = obj[i];
                }
            }
        }
        return newObj;
    }
    const deepObj = {
        name: 'lili',
        hobby: ['vball', 'tball', 'bball'],
    };
    const newDeepObj = deepClone(deepObj);
    newDeepObj.name = 'xiaoli';
    newDeepObj.hobby[0] = 'fball';
    console.log(deepObj);
    console.log(newDeepObj);

3.2.2 运用Object.entries遍历对象的属性和值实现深拷贝

 // 方式二:运用Object.entries(obj)遍历对象的属性和值
    function deepClone_property(obj) {
        let newObj = obj instanceof Array ? [] : {};
        for (const [k, v] of Object.entries(obj)) {
            newObj[k] = typeof v == 'object' ? deepClone_property(v) : v;
        }
        return newObj;
    }

    const deepObj2 = {
        name: 'lili',
        hobby: ['vball', 'tball', 'bball'],
    };
    const newDeepObj2 = deepClone_property(deepObj2);
    newDeepObj2.name = 'xiaoli';
    newDeepObj2.hobby[0] = 'fball';
    console.log('深拷贝方式二 == ', deepObj2);
    console.log('深拷贝方式二 == ', newDeepObj2);

3.3.3 使用JQuery中的$.extend()实现深拷贝(需要引入JQuery)

在线引入JQuery

<script src="https://cdn.jsdelivr.net/npm/jquery"></script>
    // 方式三:使用JQurey中的$.extend()实现深拷贝(需要引入JQuery)
    const obj33 = {
        a: 1,
        b: { f: { g: 1}},
        c: [1, 2, 3],
    };
    // $.extend()第一个参数设置为true为深拷贝,设置为false为浅拷贝
    const obj331 = $.extend(true, {}, obj33);
    const obj332 = $.extend(false, {}, obj33);
    console.log('深拷贝方式三 == ', obj33.b.f === obj331.b.f);
    console.log('深拷贝方式三 == ', obj33.b.f === obj332.b.f);

 

3.3.4 引入loadsh库使用cloneDeep实现深拷贝

    // 方式四:引入loadsh,提供cloneDeep实现
     * vue中使用loadsh库实现深拷贝的步骤:
     * 1.安装loadsh   npm i --save laadsh
     * 2.引入loadsh   import _ from 'loadsh'
     * 3.直接调用loadsh库的方法  const newObj = _.cloneDeep(this.obj)
    

 转载文章:JS 浅拷贝和深拷贝详解(巨详细)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值