前言
最近在重新学习
Javascrpt,翻看了《javascript高级设计》以及掘金上面很多大佬的博客,顺便把自己学到的东西记录下来,方便新人学习以及自己以后可以复习。希望大家看完以后能有所收获!
JS 并没有真正的数组
javascript的数组并不是真正的数组。像C、C++里面的典型的数组,它们储存的数据类型要求都是相同的,而且物理储存的位置也是连续的,能够通过数字下标来获取元素。但是在javascript中,数组的类型却可以不一样,如果数组内部有对象类型,那么对象是随机储存的,这就导致了它们储存的内存并不连续。而且javascript中并不能通过数字下标来获取元素,而是通过字符串的形式来获取元素,所以我们学习JS的时候,就经常说数组是对象类型的。
有人会问js怎么不可以通过数字下标来获取元素呢。我们来看看下面的代码。
let arr1=[1,2,3,4,5,6]
Object.keys(a) //返回的结果是['0','1','2','3','4','5']
它的所谓下标其实是字符串类型,那么为什么我一直都是使用数字下标来获取数组中的元素的呢,其实JS他通过隐式转换,将数字类型转换为字符串类型了。
let arr1=[1,2,3,4,5,6]
arr1[1]===arr1[(1).toString()]===arr1['1'] //结果返回的是2
既然数组的所谓的下标是字符串类型,那是不是我可以将它换成其他类型呢,答案是可以的。毕竟我们学JS的时候,一直都说数组是Object类型嘛,我们来试试对象类型的key与value的形式来定义一下数组的。
var arr1=[1,2,3,4,5,6]
arr1.jj=7 //返回的结果是 [1,2,3,4,5,6,jj:7] 看,是不是很眼熟,跟{key:value}很像。
一 创建一个数组
let arr=[1,2,3] //对象字面量
let arr=new Array(1,2,3) //构造器
let arr=new Array(3) //构造器,返回的结果是[empty x 10]
(1) Array.of()返回由所有参数组成的数组,不考虑参数的数量或类型,如果没有参数就返回一个空数组 。
let arr=Array.of(1,2,3) //arr=[1,2,3]
let arr1=Array.of(1) //arr1=[1]
注:Array(3)与Array.of(3)的区别。Array.of(3)创建一个具有单个元素 3 的数组,而 Array(3)创建一个长度为3的空数组。
(2) Array.from()从一个类数组或可迭代对象中创建一个新的数组。
let p= {0: 'h', 1: 'p', 2:'c', length: 3};
let arr1 = Array.from(p); // ['h','p','c'];
let arr2 = Array.from('what'); // ['w','h','a','t']
let arr = Array.from(new Set(['a','b'])); // ['a','b']
function fn(){
return Array.from(arguments);
}
fn(1,2,3) //[1,2,3]
(3) 通过转化创建数组
let arr1='1,2,3'.split(',') //arr1=[1,2,3]
let arr2='123'.split('') //arr2=[1,2,3]
二 数组的方法
1.不改变原数组的方法
(1)slice()方法返回一个从开始到结束(不包括结束)的数组到新数组对象上面
语法:
arr.slice([begin[, end]])
参数:
begin(可选): 接受负值,从该索引处开始提取原数组中的元素,默认值为0。
end(可选):接受负值,在该索引处前结束提取原数组元素,默认值为数组末尾(包括最后一个元素)。
如果省略begin,则从索引为0的开始。提取的原则是包含begin,不包含end。
--简单类型--
let arr = ['a','b','c','d','e','f'];
let arr1 = arr.slice(1,3); // arr1=['b','c'];let arr2 = arr.slice(-2,-1); // arr1=['e']
--引用类型--
let phone={color:'red',size:'small',cost:100}
let p={phone,1,"hello","world"}
let newphone=p.slice(0,2)
newphone[0].color='gray'
console.log(phone.color) // gray
也就是说在 p={phone,1,"hello","world"} 中,phone保存的是指向对象phone的指针,而对象类型在堆栈中储存的位置是同一个,所以通过这种方法修改,能够修改对象。
(2) join() 方法将数组(或一个类数组对象)中所有元素都转化为字符串并连接在一起,返回最后生成的字符串
语法:
arr.join(separator)
参数:
separator (可选):指定一个字符串来分隔数组的每个元素。如果没有填入参数,则默认使用逗号分隔。如果是空字符串,则元素之间没有字符。
let color=['yellow','red','gray']
let str1=color.join(); //'yellow,red,gray'
let str2=color.join(','); //'yellow, red, gray'
let str3=color.join(''); //'yellowredgray'
let obj=[{name:'luffy',age:19},'cap']
let str4=obj.join(); //[object object],test
let arr=[[1,2],3]
let str5=arr.join('+'); //1,2 +3
(3) toString() 返回一个字符串,表示指定的数组及其元素
语法:
arr.toString()
注意事项:
toString()和join()的方法一样,都是用于将数组转化为字符串,但是toString()不能自定义的指定分隔符,默认使用的是逗号分隔。
let arr1=[1,2,'hello','world']
arr.toString(); //1,2,hello,world
[{b:0},'hello'].toString(); //[Object Object],hello
let arr2 = [1, [2, 3], [4, 5], 6];
arr.toString() //1,2,3,4,5,6
(4) toLocaleString() 返回一个表示数组元素的字符串。该字符串由数组中的每个元素的 toLocaleString() 返回值经调用 join() 方法连接(由逗号隔开)组成
语法:
arr.toLocaleString()
let arr=[{age:13},1,'hello']
let str1=arr.tolocaleString() //[Object,Object],1,hello
(5) concat() 用于合并两个或多个数组
语法 :
arr.concat([arr1,[arr2,...arrn]])
参数:
arr1...可以是具体的值,或者是数组。当参数为空时,表示数组的浅拷贝;
let arr=[1,2,3]
let arr1=[4,5,6]
let newarr1=arr.concat(arr1); //newarr=[1,2,3,4,5,6]
let newarr2=arr.concat('hello','nice'); //newarr2=[1,2,3,'hello','nice']
let obj={a:1}
let arr3=['b',obj]
let arr4=[1,2,3].concat(arr3); // [1,2,3,'b',{a:1}]
arr4.[4].a=hi; //[1,2,3,'b',{a:'hi'}]
注意事项:
concat()不会改变this或任何作为参数提供的数组,而是返回一个浅拷贝。
concat将对象引用复制到新数组中。 原始数组和新数组都引用相同的对象。 如果引用的对象被修改,那么原始对象也会被修改。
(6)indexOf() 查找数组是否存在某个元素,返回查找到的一个个原始的下标,如果不存在则返回-1
语法:
arr.indexOf(searchElement,fromIndex)
参数:
searchElement(必填):被查找的元素
fromIndex(可选):开始查找的位置,如果查找位置大于等于索引值,返回-1。接受负值,表示从最后一个开始,默认值为0。
let arr=[1,2,3,4,5,6];
arr.indexOf(2); //2
arr.indexOf(7); //-1
arr.indexOf(3,3); //-1
arr.indexOf(2,-1); // -1 从后往前找,如果要查找的数位于起始值的前面,也是返回-1;
arr.indexOf(4,-5); //3
let arr1=[1,2,NaN]
arr1.indexOf(NaN); //-1 无法辨别NaN;
(7) lastIndexOf() 查找的方向与indexOf相反,而且是返回指定元素在数组最后一个索引
语法:
arr.lastIndexOf(searchElement,fromIndex)
参数:
searchElement (必选): 要查找的元素;
fromIndex(可选): 逆向查找开始位置,默认值数组的长度-1,即查找整个数组。如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,将其视为从数组末尾向前的偏移。当值为负值,且绝对值大于数组长度,则不会被查找;
let arr=[1,2,3,4,5,6,5,4,3,2,1]
let index1=arr.lastIndexOf(2); //9
let index2=arr.lastIndexOf(5,3); //-1
let index3=arr.lastIndexOf(5,6); //6
(8) includes() 方法用来判断一个数组是否包含一个指定的值
语法:
arr.includes(searchElement,fromIndex=0)
参数:
searchElement(必须):被查找的元素;
fromIndex(可选):默认值为0,参数表示搜索的起始位置,接受负值。正值超过数组长度,数组不会被搜索,返回false。负值绝对值超过长数组度,重置从0开始搜索。
let arr=['ok,'why',know',NaN]
let a=arr.includes('why',100); // false 超过数组长度 不搜索
lat b=arr.includes('why',-3); //true 从倒数第三个元素开始搜
let c=arr.includes('why',-100); //true 负值绝对值超过数组长度,搜索整个数组
2.改变原始数组的方法
(1)splice()在原数组的基础上添加或者删除数组元素
语法:
arr.splice(start,deleteCount,item1,.....,itemX)
参数:
start指定修改的开始位置(从0开始计数),如果超过数组长度,则是在数组末尾添加元素,如果是负数,则从末尾开始计数(末位为-1)
deleteCount表示要移除数组元素的个数,如果为零,则不移除。这种情况下是添加元素,如果 deleteCount大于start 之后的元素的总数,则从 start 后面的元素都将被删除(含第start 位)
item i指定要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。
let arr1=[1,2,3,4,5,6,7,8,9] //以下操作都不建立在前一次的操作之上的;
let a=arr1.splice(0,3); //a=>[1,2,3] arr1=>[4,5,6,7,8,9] 从第一个元素开始,删除三个元素;
let b=arr1.splice(-1,4); //b=>[9] arr1=>[1,2,3,4,5,6,7,8] 从最后一个元素开始,删除四个元素,但是最后一个只有一个元素,所以只删除一个元素
let c=arr1.splice(2,0,'hi'); //c=>[] arr1=>[1,2,'hi',3,4,5,6,7,8,9] 从第三个元素开始删除零个,并在该位置插入字符串,其他的元素后移
let d=arr1.splice(3,4,'what'); //d=>[4,5,6,7] arr1=>[1,2,3,'what',8,9] 从第四个元素开始,删除四个元素,并插入一个字符串
let e=arr1.splice(3); //e=>[4,5,6,7,8,9] arr1=>[1,2,3] 从第四个元素开始删除,只剩下前三个
let f=arr1.splice(-4,2,'uu'); f=>[6,7] arr1=>[1,2,3,4,5,'uu'8,9] 从倒数第四位开始,删除2个数,并插入一个字符串
(2)sort()将数组中的元素排序并返回排序后的数组
语法:
arr.sort([compareFunction])
参数:
compareFunction用来指定按照某种顺序进行排列,如果省略,元素按照转换为字符串的各字符串的Unicode的位点来进行排列。如果不省略,则数组会按照调用该函数的返回值进行排序。
如果比较函数返回值<0,那么a将排到b的前面;
如果比较函数返回值=0,那么a和b相对位置不变;
如比较函数返回值>0,那么b 排在a将的前面;
let arr1=[1,4,3,2,7]
arr1.sort((a,b)=>{
if(a>b){
return 1;}else if(a===b){
return 0;
}else{
return -1}
)
console.log(arr1) //[1,2,3,4,7]
--数组的元素是对象--
let arr2=[{id:2,name:'lisa'},{id:1,name:'homey'},{id:3,name:'barz'}]
arr2.sort((a,b)=>{
return a.id-b.id;
}) //上面的判断也可以直接写成该形式;
//{id:1,name:'homey'},{id:2,name:'lisa'},{id:3,name:'barz'}
(3) push()将一个或多个元素添加到数组的末尾,并返回该数组的新长度
语法:
arr.push(element1, ..., elementN)
参数:
element i表示要添加到数组末尾的元素
let arr=[1,2,3] //以下操作都不建立在前一次的操作之上的;
let item1=arr.push([4,5,6]) //item1=4 arr=[1,2,3,[4,5,6]]
let item2=arr.push({name:'hi'}) // item2=4 arr=[1,2,3,{name:'hi'}]
let item3=arr.push(6,7,8,'ok') //item3=7 arr=[1,2,3,6,7,8,'ok']
(4) pop() 删除数组的最后一个元素,减小数组长度并返回它删除的值。
语法:
arr.pop()
无参数
let arr=[1,2,3,'fine','purified',{name:'judy'}]
let item1=arr.pop() // item1={name:'judy'} arr=[1,2,3,'fine','purified']
(5)shift()从数组中删除第一个元素,并返回该元素的值。
语法:
arr.shift()
无参数
let arr=[1,2,3,'angel','vertify',[1,2,3]]
let item=arr.shift() // 1 arr=[2,3,'angel','vertify',[1,2,3]]
(6) unshift()将一个或多个元素添加到数组的开头,并返回该数组的新长度。
语法:
arr.unshift(element1, ..., elementN)
参数:
element i表示要插入到数组前面的元素
let arr=[1,2,3] //以下操作都不建立在前一次的操作之上的;
let item1=arr.unshift(6,7,8) //item1=6 arr=[6,7,8,1,2,3]
let item2=arr.unshift(['a','b','c']) //item2=4 arr=[['a','b','c'],1,2,3]
(7) reverse() 将数组中的元素颠倒顺序,返回逆序的数组。
语法:
arr.reverse()
无参数
let a=[1,2,3]
let item=a.reverse() //item=[3,2,1] a=[3,2,1]
(8) copyWithin()浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
语法:
array.copyWithin(target, start = 0, end = this.length)
参数:
target表示从该位置开始替换数据,如果是负值,表示从后往前计;
start表示开始复制元素的开始位置,如果是负数,表示从后往前计;
end表示开始负值元素的结束位置,而且不包含end的元素,如果是负数,则表示从后往前计,如果忽略,则会复制到末尾;
let arr=[1,2,3] //以下操作都不建立在前一次的操作之上的;
let item1=arr.copyWithin(0, -2, -1) //item1=[2,2,3] arr=[2,2,3]
let item2=arr.copyWithin(0, 1) //item2=[2,3,3] arr=[2,3,3]
(9) fill() 用一个固定值填充一个数组中从起始索引到终止索引内的全部元素,且数组长度不会改变。
语法:
arr.fill(value[, start[, end]] )
参数:
value用来填充数组元素的值。
start表示起始索引,默认值为0。
end终止索引,默认值为 this.length。
let arr=[1,2,3,4,5] //以下操作都不建立在前一次的操作之上的;
let item1=arr.fill(6) //item1=[6,6,6,6,6] arr=[6,6,6,6,6]
let item2=arr.fill(8,1,3) //item2=[1,8,8,4,5] arr=[1,8,8,4,5]
3 遍历方法
(1)forEach() 按升序为数组中含有效值的每一项执行一次回调函数。
语法:
arr.forEach(callback(currentValue, index, arr), thisArg)
参数:
currentValue表示数组中正在处理的当前元素。
index表示数组中正在处理的当前元素的索引。
arr表示正在被处理的数组。
thisArg默认指向undefined,当使用箭头函数时,该参数被忽略;
注意事项:
forEach()无法中途退出循环,只能使用return 退出本次回调,进行下一次回调;该方法总是返回undefined,即使指定让他return一个值也没用;
空元素不会遍历,但undefined和unll会遍历;
在迭代过程中删除的元素,或者空元素会跳过回调函数;
遍历次数在一开始就已经确定了,再迭代过程中添加到数组的元素不会被遍历;
如果已经存在的值被改变,则传递给 callback 的值是遍历到他们那一刻的值。
let arr1 = ['a','b', ,null,undefined,'c'];
arr1.forEach((value,index,arr)=>{
console.log(value,index,arr)
}) //'a' 0 ['a','b',empty,null,undefined,'c'] 'b' 1 ['a','b',empty,null,undefined,'c'] null 3 ['a','b',empty,null,undefined,'c'] undefined 4 ['a','b',empty,null,undefined,'c'] 'c' 5 ['a','b',empty,null,undefined,'c']
-----------
let arr2=[1,2,3]
arr2.forEach((value,index,arr)=>{
if(index===0){
delete arr2[2];
}
console.log(value,index,arr)
}) //1 0 (3) [1, 2, empty] 2 1 (3) [1, 2, empty]
----------
let arr3 = ['a','b','c','d'];
arr3.forEach((value,index,arr)=> {
if(index === 1) {
arr3.shift() //遍历到第二项的时候,删除第一项
}
console.log(value,index,arr)
})
// 打印信息如下,遍历到第二项的时候,删除第一项,会跳过第三项
// a 0 (4) ['a','b','c','d'] b 1 (3) ['a','b','d'] d 2 (3) ['a','b','d']
(2) map()创建一个新数组,其结果是该数组中的每个元素都调用一个callback函数后返回的结果。
语法:
arr.map(function(currentValue, index, arr), thisArg)
参数:
同foreach()
注意事项:
map()不修改被调用的数组。它具有与原数组相同的长度。
let arr=[1,3,5,7,9]
let newarr=arr.map((item,index)=>{ //newarr=[1,6,10,14,18]
return item*2;}) //如果不使用return 那么返回的新对象则是undefined;
(3)filter()返回一个新数组, 其包含通过所提供函数实现的测试的所有元素。
语法:
arr.filter(function(currentValue, index, arr), thisArg)
参数:
同foreach()
let arr=[12,4,47,55,19,38]
let newarr=arr.filter((item,index)=>{
return item>30;
}) //newarr=[47,55,58]
(4)some()判断数组中的元素是否有元素符合判断条件,当且仅当所有元素都不符合条件时,才返回false;
语法:
arr.some(function(currentValue, index, arr), thisArg)
参数:
同foreach()
let arr=[1,2,3,4,5,6,7,8]
arr.some(item=>{
return item%2===1}) //true
当然也可以封装成为一个函数
function isodd(ele,index){
return ele%2===1}
let result =arr.some(isodd); //true
(5) every()判断数组中的元素是否都符合判断条件,当且仅当所有元素都符合条件时,才返回true;
语法:
arr.every(function(currentValue, index, arr), thisValue)
参数:
同foreach()
let arr=[1,2,3,4,5,6,7,8]
arr.every(item=>{
return item%2===1}) //false
当然也可以封装成为一个函数
function isodd(ele,index){
return ele%2===1}
let result =arr.every(isodd); //false
(6)reduce()使用指定的函数将数组元素进行组合,生成单个值。reduceRight()则从右往左进行相同的操作。
语法:
arr.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数:
total为累加器
currentValue数组当前元素的值
index 当前元素的索引值
initialValue 指定第一次回调 的第一个参数。
注意事项:
如果 initialValue 在调用 reduce 时被提供,那么第一个 total 将等于 initialValue,此时 currentValue 等于数组中的第一个值;
如果 initialValue 未被提供,那么total 等于数组中的第一个值,currentValue 等于数组中的第二个值。此时如果数组为空,那么将抛出TypeError;
如果数组仅有一个元素,并且没有提供initialValue,或提供了 initialValue 但数组为空,那么回调不会被执行,数组的唯一值将被返回;
----当initialValue为0时----
let arr=[1,2,3,4]
let sum1=arr.reduce((total,currentvalue)=>total+currentvalue,0);
console.log(sum1) //10
----当initialValue不为0时-----
let arr=[1,2,3,4]
let sum2=arr.reduce((total,currentvalue)=>total+currentvalue,5);
console.log(sum2) //15
---使用reduce模拟map---
let arr=[1,2,3,4,5]
let result1=arr.reduce((result,item)=>{return rsult.concat(item*item)},[])
console.log(result1) //[1,4,9,16,25]
---使用reduce模拟filter---
let arr=[1,2,3,4,5]
let result2=arr.reduce((result,item)=>{
if(item%2===1){
return result
}else{
return result.concat(item)
}},[])
console.log(result2) //[2,4]
(7)find()查找第一个复合条件的元素,并返回该元素,否则返回undefined;findIndex()查找第一个复合条件的元素,并返回该元素的索引,否则返回-1
语法:
let element =arr.find(function(elemnet, index, arr), thisArg)
let index = arr.findIndex(function(elemnet, index, arr), thisArg)
参数:
同foreach()
---find()---
let arr=[1,3,7,9,13,16]
let a=arr.find((item,index)=>item>10) //a=13
let b=arr.find((item,index)=>item>20) //b=undefined
---findIndex()---
let c=arr.findIndex((item,index)=>item<-1) //c=-1
let d=arr.findIndex((item,index)=>item>5) //d=2
(8)keys() 、values()、entries()返回一个新的数组迭代器,分别是包含数组中每个索引的键或者是值或者是键与值。
语法:
arr.keys()
arr.values()
arr.entries()
无参数
---keys()---
let arr=['a','b','c']
let a=Object.keys(arr) //a=['0','1','2']
---keys()---
let arr=['a','b','c']
let b=Object.values(arr) //b=['a','b','c']
---entries()---
let arr=['a','b','c']
let c=Object.values(arr) //c=[['0','a'],['1','b'],['2','c']]
总结
花了几天的零碎时间整理了至ES6的几乎所有的数组的操作方法,在参考了许多大佬的博客以及官方文档后,对数组的许多API的理解也更加深入了。文章如有不正确的地方欢迎各位大佬鞭策!