JavaScript 数组的一些方法&&数组拷贝
一、添加/删除
1、Array.unshift(newEle , newEle2 , newEle3 , ...)(改变原数组)
向数组的 开头 添加一个或更多元素,并返回新的长度
队列方法 栈数据结构的访问规则是LIFO(Last-In-First-Out,后进先出),而队列数据结构的访问规则是FIFO(First-In-First-Out,先进先出)
let a = [1,2,3,4,5];
let b = a.unshift(-2,-1);
//a:[-2,-1,1,2,3,4,5]
//b:7
2、Array.push(newEle , newEle2 , newEle3 , ...)(改变原数组)
向数组的 结尾 添加一个或更多元素,并返回新的长度
栈方法 栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构
let a = [1,2,3,4,5];
let b = a.push(6 , 7);
//a:[-2,-1,1,2,3,4,5,6,7]
3、Array.shift()(改变原数组)
删除原数组 第一项,并返回删除元素的值;如果数组为空则返回undefined
队列方法 栈数据结构的访问规则是LIFO(Last-In-First-Out,后进先出),而队列数据结构的访问规则是FIFO(First-In-First-Out,先进先出)
let a = [1,2,3,4,5];
let b = a.shift();
//a:[2,3,4,5]
//b:1
4、Array.pop()(改变原数组)
删除原数组 最后一项,并返回删除元素的值;如果数组为空则返回undefined
栈方法 栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构
let a = [1,2,3,4,5];
let b = a.pop();
//a:[1,2,3,4]
//b:5
5、Array.concat(arr , arr2 , arr3 , ...)(不改变原数组)
连接值或其他数组
let a = [1,2,3,4,5];
let b = a.concat(6,7);
//a:[1,2,3,4,5]
//b:[1,2,3,4,5,6,7]
6、Array.slice(start,end)(不改变原数组)
从已有的数组中返回选定的元素 start包含 , end不包含
它和字符串的str.slice(start, end)方法类似, 就是将字符串替换为数组
let a = [1,2,3,4,5];
let b = a.slice(2,5);
//a:[1,2,3,4,5]
//b:[3,4,5]
我们也可以不带参数地调用它:arr.slice()会创建一个arr的副本。其通常用于获取副本,以进行不影响原始数组的进一步转换。
7、Array.splice(index,num,newEle ,newEle 2,newEle 3,...)(改变原数组)
(我是宠儿我自豪)
向/从数组中添加/删除项目,然后返回被删除的项目
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
num 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
newEle , newEle2 , ... 可选。向数组添加的新项目。
返回包含被删除项目的新数组,如果有的话。
let a = [1,2,3,4,5];
let b = a.splice(1,1);
//a: [1,3,4,5]
//b: [2]
a.splice(1,0,55);
//a:[1,55,2,3,4,5]
//b:[]
------------------------------假装分割线------------------------------
二、遍历
1、Array.forEach(改变原数组)
它允许为数组的每个元素都运行一个函数,该函数的结果(如果它有返回)会被抛弃和忽略。
------------------------------假装分割线------------------------------
三、转换
1、Array.map(改变原数组)
对数组的每个元素都调用函数,并返回结果数组
let arr = ["zhangsan", "lisi", "wangwu"].map(item => item.length);
console.log(arr); // 8,4,6
2、Array.sort(fn)(改变原数组)
对数组的元素进行排序,fn为排序方法函数
function sortFn(a,b){
return a - b
}
let a = [1,3,5,4,2];
a.sort(sortFn)
//a: [1,2,3,4,5]
3、Array.reverse()(改变原数组)
数组倒序排列
let a = [1,2,3,4,5];
let b = a.reverse();
//a:[5,4,3,2,1]
//b:[5,4,3,2,1]
4、Array.join(str)(不改变原数组)
方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的
如果不填参数,则使用逗号作为分隔符
let a = [1,2,3,4,5];
a.join('-')
//a: [1,2,3,4,5]
//b: 1-2-3-4-5
5、reduce/reduceRight(fn, initial)
第一个参数fn为一个累加函数, 第二个initial为初始值 如果不填写默认将arr的第一个为初始值
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
console.log(result); // 15
------------------------------假装分割线------------------------------
四、搜索
1、Array.indexOf(item, from)/lastIndexOf(item, from)(不改变原数组)
返回某个指定的字符串值在字符串中首次出现的位置,对大小写敏感,没有出现指定字符串则返回-1
let a = [1,2,3,4,5];
let b = a.indexOf(2);
//a: [1,2,3,4,5]
//b: 1
2、Array.includes
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。
该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
没有该方法之前,我们通常使用数组的indexOf方法。indexOf方法有两个缺点:
一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。
二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判
3、Array.find() / findIndex()
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 4, -5, 10].find((n) => n < 0)
// -5
4、Array.filter
find 方法搜索的是使函数返回 true 的第一个(单个)元素。
如果需要匹配的有很多,我们可以使用 arr.filter
语法与 find 大致相同,但是 filter 返回的是所有匹配元素组成的数组:
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
// 返回前两个用户的数组
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2
------------------------------假装分割线------------------------------
五、其它
ES6 数组的拓展
1、Array.from()
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
如果参数是一个真正的数组,Array.from会返回一个一模一样的新数组
2、Array.of
Array.of方法用于将一组值,转换为数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。
3、数组实例的 copyWithin()
数组实例的copyWithin()方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
它接受三个参数。
- target(必需):从该位置开始替换数据。如果为负值,表示倒数。
- start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
上面代码表示将从 3 号位直到数组结束的成员(4 和 5),复制到从 0 号位开始的位置,结果覆盖了原来的 1 和 2。
4、数组实例的fill()
fill方法使用给定值,填充一个数组。
fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
5、数组实例的entries(),keys()和values()
ES6 提供三个新的方法——entries(),keys()和values()——用于遍历数组。它们可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
如果不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历
5、数组实例的flat()、flatMap()
数组的成员有时还是数组,Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。
[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
------------------------------假装分割线------------------------------
六、数组拷贝
1、拓展运算符 【...】
扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
注意,只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错
const a1 = [1, 2];
const a2 = a1;
a2[0] = 2;
a1 // [2, 2]
上面代码中,a2并不是a1的克隆,而是指向同一份数据的另一个指针。修改a2,会直接导致a1的变化。
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
上面的两种写法,a2都是a1的克隆
2、concat()
连接值或其他数组
如果我们不指定参数或者提供一个空数组作为参数,浅拷贝方法
const arr1 = [1, 2, 3, 4]
const arr2 = arr1.concat()
console.log('before push arr2', arr2) // [1, 2, 3, 4]
arr2.push(5)
console.log('after push arr1 :', arr1) // [1, 2, 3, 4]
console.log('after push arr2 :', arr2) // [1, 2, 3, 4, 5]
3、slice()
slice方法根据我们指定的start、end的index从原数组中返回一个浅拷贝的数组
当不给定参数时,就返回了原数组的拷贝
const arr1 = [1, 2, 3, 4]
const arr2 = arr1.slice(0,2)
console.log('before push arr2', arr2) // [1, 2, 3, 4]
arr2.push(5)
console.log('after push arr1 :', arr1) // [1, 2, 3, 4]
console.log('after push arr2 :', arr2) // [1, 2, 5]
4、Array.from
Array.form 方法从一个类似数组或可迭代对象中创建一个新的,浅拷贝的数组实例
console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]
console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]
手动分割线
let str = 'abc'
let strArr = Array.from(str)
console.log(strArr) // ['a', 'b', 'c']
let arr = [1, 2, 3, 4]
let brr = Array.from(arr)
console.log(brr) // [1, 2, 3, 4]
arr.push(5)
brr.push(10)
console.log(arr) // [1, 2, 3, 4, 5]
console.log(brr) // [1, 2, 3, 4, 10]
5、JSON.parse & JSON.stringify(深拷贝)
let arr = [[1], [2]]
let brr = JSON.parse(JSON.stringify(arr))
console.log(brr) // [[1], [2]]
brr[0].push(6)
console.log(arr) // [[1], [2]]
console.log(brr) // [[1, 6], [2]]
此方法适用于Oject的深度拷贝,因为Array属于Oject类型,所以也适用于此处
注意事项参考 :
①、如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
②、如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象
③、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
④、 如果obj里有NaN、Infinity或-Infinity,则序列化的结果会变成null
⑤、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor
6、对象数组的深拷贝
let obj = {
name: 'zhangsan',
age: 28,
children: [
{ name: 'zhangsi', age: 2 }
]
}
function deepClone(tdata, odata) {
for (let k in tdata) {
// 判断数据类型
let item = tdata[k]
if (item instanceof Array) {
odata[k] = []
deepClone(item, odata[k])
} else if (item instanceof Object) {
odata[k] = {}
deepClone(item, odata[k])
} else {
odata[k] = item
}
}
return odata
}
let tx = deepClone(obj, {})
console.log('deep test:', tx)
转载自:https://juejin.cn/post/7383957603016245263