slice() 方法
数组截取办法: slice() ,用于截取数组中的一部分,返回一个新的数组对象,不影响原数组。arr.slice(begin, end) ,slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 begin ,但不包含 end )。 注意 ? ? ? slice() 方法是浅拷贝,具体在下文做解释。
slice() ,用于截取数组中的一部分,返回一个新的数组对象,不影响原数组。
注意 ? ? ? slice() 方法是浅拷贝,具体在下文做解释。
arr.slice(begin, end) ,slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 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.修改对象深层属性")
menuTreeList[0].children = [];
console.log('被修改过的原来的数组 menuTreeList :>> ', menuTreeList);
console.log('新的数组 a :>> ', a);
console.groupEnd()
let newArr = [1, 2, 3, 4, 5, 6];
let b = newArr.slice(0, 4);
console.group("2.验证数组元素为字符串、数字及布尔值时的情况")
newArr[0] = 0;
newArr[1] = 0;
newArr[2] = 0;
newArr[3] = 0;
console.log('被修改过的原来的数组 newArr :>> ', newArr);
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.修改简单对象的属性 验证")
newArr3[0].id = "111111111";
newArr3[1].id = "111111111";
newArr3[2].id = "111111111";
console.log('被修改过的原来的数组 newArr3 :>> ', newArr3);
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.把数组简单对象置空 验证")
newArr2[0] = {};
newArr2[1] = {};
newArr2[2] = {};
console.log('被修改过的原来的数组 newArr2 :>> ', newArr2);
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);
console.log('新的数组 e :>> ', e);
console.groupEnd()
输出结果: 为什么把数组简单对象元素改为基本数据类型 和把数组简单对象置空 这两种情况下的数组都没有跟着改变呢?
这个问题我是向 CSDN博客专家「零一」学习的,字节跳动大佬,很多高质量原创文章,快来观摩👉?「零一」?👈
问题解析:
我们可以这样理解,[q, w, e] ,其实这个数组中第一个元素就是变量q,它指向的是一个对象
- 如果修改该对象内部的属性,那么变量q仍然只是指向这个对象,对象的内存地址没变
- 如果直接把数组中第一个元素修改为空对象,那么就相当于
q = {} ,那指向的肯定跟原来的不一样了
即原来数组里的元素改为了新的对象,使用了新的对象引用,新数组里的元素对象依然存储在堆里,使用的是旧的对象引用。
我们接着看下面这个例子:
let newArr6 = [{
"id": "1",
"name": "设备管理",
"menuType": 0,
}, {
"id": "2",
"name": "设备管理",
"menuType": 0,
}, {
"id": "3",
"name": "设备管理",
"menuType": 0,
}, {
"id": "4",
"name": "设备管理",
"menuType": 0,
}];
let f = newArr6.slice(0, 3);
console.group("6.把数组简单对象设置为新的对象 验证")
newArr6[0] = {
"sss": "4444",
"aaaa": "对方是否",
};
newArr6[1] = {
"sss": "4444",
"aaaa": "对方是否",
};;
newArr6[2] = {
"sss": "4444",
"aaaa": "对方是否",
};;
console.log('被修改过的原来的数组 newArr6 :>> ', newArr6);
console.log('新的数组 f :>> ', f);
console.groupEnd()
输出结果: 其实不管是把对象改为基本数据类型,还是重新赋一个新的对象,他们都属于一类,都是修改了对象的指向
原来数组里的元素指向了新的内存引用,新数组里的元素指向的是旧的内存引用,所以原来数组里的元素改为一个基本数据类型值,或者改为一个新的对象,或者空对象,并不会对新数组产生影响,因为他们数组元素的内存指向已经不一样了。
基本对象引用赋值的浅拷贝
这里和基本的对象引用赋值做一个对比:
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;
console.group("1.修改对象深层属性")
menuTreeList[0].children = [];
console.log('被修改过的原来的数组 menuTreeList :>> ', menuTreeList);
console.log('新的数组 a :>> ', a);
console.groupEnd()
let newArr = [1, 2, 3, 4, 5, 6];
let b = newArr;
console.group("2.验证数组元素为字符串、数字及布尔值时的情况")
newArr[0] = 0;
newArr[1] = 0;
newArr[2] = 0;
newArr[3] = 0;
console.log('被修改过的原来的数组 newArr :>> ', newArr);
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;
console.group("3.修改简单对象的属性 验证")
newArr3[0].id = "111111111";
newArr3[1].id = "111111111";
newArr3[2].id = "111111111";
console.log('被修改过的原来的数组 newArr3 :>> ', newArr3);
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;
console.group("4.把数组简单对象置空 验证")
newArr2[0] = {};
newArr2[1] = {};
newArr2[2] = {};
console.log('被修改过的原来的数组 newArr2 :>> ', newArr2);
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;
console.group("5.把数组简单对象元素改为基本数据类型 验证")
newArr4[0] = 0;
newArr4[1] = 0;
newArr4[2] = 0;
console.log('被修改过的原来的数组 newArr4 :>> ', newArr4);
console.log('新的数组 e :>> ', e);
console.groupEnd()
参考
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
|