如何理解 slice() 方法是浅拷贝?深入数组浅拷贝里的小细节

文章目录

slice() 方法

数组截取办法: slice(),用于截取数组中的一部分,返回一个新的数组对象,不影响原数组。arr.slice(begin, end)slice 会提取原数组中索引从 beginend 的所有元素(包含 begin,但不包含 end)。 注意 ❗ ❗ ❗ slice()方法是浅拷贝,具体在下文做解释。

slice(),用于截取数组中的一部分,返回一个新的数组对象,不影响原数组。

注意 ❗ ❗ ❗ slice()方法是浅拷贝,具体在下文做解释。

arr.slice(begin, end)slice 会提取原数组中索引从 beginend 的所有元素(包含 begin,但不包含 end)。

begin 可选 是提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。

  • 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。

  • 如果省略 begin,则 slice 从索引 0 开始。

  • 如果 begin 超出原数组的索引范围,则会返回空数组。

end 可选 是提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 begin,但不包含 end)。

  • slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。

  • 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。

  • 如果 end 被省略,则 slice 会一直提取到原数组末尾。

  • 如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。

如何理解 slice() 方法的浅拷贝

slice 不会修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:

  • 如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
  • 对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

如果向两个数组任一中添加了新元素,则另一个不会受到影响。

下面通过实例详细了解一下 slice()方法的浅拷贝:

下面的代码描述了修改数组的几种情况:

let menuTreeList = [{
                "id": "cfda8029dfb311e7b555201a068c6482",
                "name": "系统管理",
                "menuType": 0,
                "children": [{
                    "id": "3873ccc2dfda11e7b555201a068c6483",
                    "name": "菜单管理",
                    "menuType": 2,
                    "children": [{
                            "id": "18bf8d5df09511e78a57201a068c6484",
                            "name": "新增",
                            "menuType": 1
                        },
                        {
                            "id": "18bf8d5df09511e78a57201a068c6485",
                            "name": "修改",
                            "menuType": 1
                        }
                    ]
                }]
            },
            {
                "id": "cfda8029dfb311e7b555201a068c6486",
                "name": "设备管理",
                "menuType": 0,
                "children": [{
                        "id": "18bf8d5df09511e78a57201a068c6487",
                        "name": "新增",
                        "menuType": 1
                    },
                    {
                        "id": "18bf8d5df09511e78a57201a068c6488",
                        "name": "修改",
                        "menuType": 1
                    }
                ]
            }
        ]

 let a = menuTreeList.slice(0, 1);
 console.group("1.修改对象深层属性")
 // console.log('a :>> ', a);
 // 1.被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变:
 //   修改原始值 menuTreeList[0] ,即修改对象的引用
 menuTreeList[0].children = [];
 // 验证: 
 // 原来的数组:
 console.log('被修改过的原来的数组 menuTreeList :>> ', menuTreeList);
 // slice方法产生的新数组:
 console.log('新的数组 a :>> ', a);
 console.groupEnd()



 let newArr = [1, 2, 3, 4, 5, 6];
 let b = newArr.slice(0, 4);
 console.group("2.验证数组元素为字符串、数字及布尔值时的情况")
 // console.log('b :>> ', b);
 // 2.对于字符串、数字及布尔值来说,slice 会拷贝这些值到新的数组里。
 //   在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组:
 newArr[0] = 0;
 newArr[1] = 0;
 newArr[2] = 0;
 newArr[3] = 0;
 // 原来的数组:
 console.log('被修改过的原来的数组 newArr :>> ', newArr);
 // slice方法产生的新数组:
 console.log('新的数组 b :>> ', b);
 console.groupEnd();



 let newArr3 = [{
     "id": "1",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "2",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "3",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "4",
     "name": "设备管理",
     "menuType": 0,
 }];

 let d = newArr3.slice(0, 3);
 console.group("3.修改简单对象的属性 验证")
 // console.log('d :>> ', d);
 newArr3[0].id = "111111111";
 newArr3[1].id = "111111111";
 newArr3[2].id = "111111111";
 // 原来的数组:
 console.log('被修改过的原来的数组 newArr3 :>> ', newArr3);
 // slice方法产生的新数组:
 console.log('新的数组 d :>> ', d);
 console.groupEnd();



 let newArr2 = [{
     "id": "1",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "2",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "3",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "4",
     "name": "设备管理",
     "menuType": 0,
 }];
 let c = newArr2.slice(0, 3);
 console.group("4.把数组简单对象置空 验证")
 // console.log('c :>> ', c);
 newArr2[0] = {};
 newArr2[1] = {};
 newArr2[2] = {};
 // 原来的数组:
 console.log('被修改过的原来的数组 newArr2 :>> ', newArr2);
 // slice方法产生的新数组:
 console.log('新的数组 c :>> ', c);
 console.groupEnd()



 let newArr4 = [{
     "id": "1",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "2",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "3",
     "name": "设备管理",
     "menuType": 0,
 }, {
     "id": "4",
     "name": "设备管理",
     "menuType": 0,
 }];

 let e = newArr4.slice(0, 3);
 console.group("5.把数组简单对象元素改为基本数据类型 验证")
 newArr4[0] = 0;
 newArr4[1] = 0;
 newArr4[2] = 0;
 // 原来的数组:
 console.log('被修改过的原来的数组 newArr4 :>> ', newArr4);
 // slice方法产生的新数组:
 console.log('新的数组 e :>> ', e);
 console.groupEnd()

输出结果:
如何理解 slice() 方法是浅拷贝?深入数组浅拷贝里的小细节
如何理解 slice() 方法是浅拷贝?深入数组浅拷贝里的小细节
为什么把数组简单对象元素改为基本数据类型把数组简单对象置空这两种情况下的数组都没有跟着改变呢?

这个问题我是向 CSDN博客专家「零一」学习的,字节跳动大佬,很多高质量原创文章,快来观摩

上一篇:图解 Slice 操作


下一篇:成功解决TypeError: slice indices must be integers or None or have an __index__ method