数组是有序的集合,有序很重要,逗号隔开,逗号很重要。每一个值叫元素,而每个元素在数组中有一个位置,以数字表示(关联数组除外),称为索引。数组是无类型的,数组元素可以是任意类型,包括数组自身,数组可以创建极其复杂的结构。
数组第一个元素的索引是0,最大可能的索引为4 294 967 294 (2的32次方-2),有看过我入门ES6文章的小伙伴应该知道,JavaScript中最大的整数是2的53次方,称之为最大的安全整数,再往上就取不到了,但是由于外国人是喜欢从0开始,所以2的53次方-1是边界
其实本来想写函数的,但是函数深入起来太难,之后编写底层机制的时候再深入,本期数组也是快速过
创建数组
字面量就不解释了,简单介绍构造函数形式
var a = new Array() == var a=[]
如果我们传入一个参数数字
var a = new Array(5) == var a=[,,,,,]
console.log(a) // [empty*5] 空的*5
console.log(a[0]) // undefined 如果省略数组的值,省略的元素将赋予undefined 不是null
如何判断数组为空,可能之前小伙伴写多了value为空,对象为空,这边也是做个提醒
var a=null
var b=undefined
var c=""
var d=[]
var e=[]
var f=[]
d.push(a)
e.push(b)
f.push(c)
console.log(d,d.length,d[0])
console.log(e,e.length,e[0])
console.log(f,f.length,f[0])
很明显都是有值的,因为数组可以存储所有类型,如何判断数组为空呢
var a=null
var b=undefined
var c=""
var d=[]
var e=[]
var f=[]
d.push(a)
e.push(b)
f.push(c)
d.length=0
e.length=0
f.length=0
console.log(d,d.length,d[0])
console.log(e,e.length,e[0])
console.log(f,f.length,f[0])
改变数组长度为0即可,写逻辑判断的时候注意一下
对了,刚才有个错误,就是前面创建
var a = new Array(5) == var a=[,,,,,]
这里是不等价的,结果相同结构不同,使用构造函数定义的数组,如果只是传入一个数字相当于用来预分配了一个数组空间,没有存储值没有索引也就是说没有a[index]这种写法,但是右边的存在索引写法,注意一下
其实数组很多博客都有介绍比我详细的多,我主要就写一些比较冷门的数组知识,数组方法也过一遍,然后数组排序以及数组去重写几个方法
稀疏数组
稀疏数组就是包含从0开始的不连续索引数组。通常,数组的length属性值代表数组中元素的个数,如果数组是稀疏的,length大于元素个数。可以使用Array()构造函数或简单地指定数组的索引值 大于当前的数组长度创建稀疏数组
a=new Array(5) //数组没有元素,但是a.length=5
a=[] //创建一个空数组,length=0
a[1000]=0 //赋值添加一个元素,但是length为1001
在数组字面量创建的时候如果省略值不会创建稀疏数组。刚才提过省略的数组是存在值的,因此索引是存在的。可以使用in区别一下,但这里有个误区我们要排排
const a1 = [undefined, undefined, undefined];
const a2 = [, , ,];
a1.length // 3
a2.length // 3
a1[0] // undefined
a2[0] // undefined
a1[0] === a2[0] // true
所以为什么我们说未定义数组内容的时候,其实是有值并且值就是undefined,因为它们是全等的情况,但是看这种情况
var a=[,undefined]
console.log(0 in a,1 in a) // false true
第一个索引0 没有值(false) 第二个索引 1 有值(true), a=new Array(5)这种就不用测了,都是false
那么小伙伴要注意一下这种情况,毕竟布尔值判断条件指不定就被误区给搞砸了,不过我们一般都是操作非稀疏数组的
我们之前聊对象的时候说过,所有的对象都是关联数组,所以数组也可以使用对象方法,简单用一下
var arr=[1,2,3]
Object.defineProperty(arr,'length',{writable:false}) //设置不可操作length
arr.length=0;
console.log(arr) // 123
直接冻结就很刺激了
直接操作数组方法好了,其实很多时候我们都在操作数组方法而已
length属性很强大,清空设置为0,删除后面元素减少length,灵活运用大大提高了开发效率
console.log(Array.prototype) 查看数组方法
以下方法不按顺序,想到什么写什么
join 转字符串
Array.join( )返回最后生成的字符串,返回什么很重要
var a=[1,2,3]
var str=a.join() //括号内的参数代表字符串直接的分隔符,默认是逗号
var strs=a.join('')
var strss=a.join(' ')
var strsss=a.join('-')
console.log(str,strs,strss,strsss) //"1,2,3" "123" "1 2 3" "1-2-3"
该方法在开发比较常用,字符串数组互相转换,也有简单粗暴直接toString(),多维数组都遭不住直接变字符串,如果面试有这种题,多维数组转一维数组,直接toString 然后split即可(我在想待会要不要找几道面试题耍耍)
reverse 倒转
Array.reverse()返回逆序的数组,这个数组它的引用并没有改变,在原数组的基础上进行操作
var a=[1,2,3]
a.reverse()
console.log(a) // 3 2 1
sort 排序
Array.sort()方法将数组中的元素排序并返回排序后的数组 ,该方法有一些坑
var arr=['a','b','z',undefined,'y']
arr.sort()
console.log(arr) // a b y z undefined
首先sort只针对值的第一个字母操作,并且如果有值是undefined 直接排最后
var arr=[11,2,3,4,5]
arr.sort()
console.log(arr) // 11 2 3 4 5
这种情况肯定不是我们想要的,所以我们都会在sort中传个参数规定一下
函数是可以当成参数的,每个函数的返回结果都是return后面的内容,函数的结果只与return有关
var arr=[11,2,3,4,5]
arr.sort(function(a,b){
return a-b
})
console.log(arr) // 2 3 4 5 11
为什么return一个a-b就是升序了呢,反过来b-a就是降序呢
抛开原理不讲,给一个记忆方法。两个参数a,b 如果返回前一个减后面一个就是升序,相当于a b c层级上升,那反过来就是降,那我是这么记的
为什么a-b是升,如果 a-1 && <1,则表示 a 和 b 具有相同的排序顺序。若返回值>=1,则表示 a 在排序后的序列中出现在 b 之后。假设a>b ,return a-b>=1,那么排序就是b,a,为升序;反之return b-a<=-1,那么排序就是a,b,为降序,也就是说它会根据负数、0、正数相应顺序返回,理解的不了的还是记上方的内容 ,而且如果是字符串机制就多了一步,这里使用匿名函数非常方便,既然只使用一次就没必要命名了
var arr=['and','Bug','Dog','cat']
arr.sort()
console.log(arr) //["Bug", "Dog", "and", "cat"]
其实没毛病,不过这不是我们想要的
在字符串中,字符串的比较是从左边开始依次比较,跟长度无关,一旦比出大小就结束比较,比较依据就是Unicode编码,它是ASCII和Latin-1的超集,并支持地球上几乎所有在使用的语言,什么阿拉伯啊,什么数学公式啊都支持
这里我们番外一下啊,比如我们自定义一个字符串文字,看看它的编码以及编码值
var a='中'
var code=a.charCodeAt()//编码值
console.log("\\u"+code.toString(16)) //因为Unicode的编码值格式都是有加\u的,这里为什么多加一个\呢,
//因为只有一个\代表引用,如果想引用'\'就必须在 \前面再加一个\ 看过我正则的应该不难理解哈
console.log(String.fromCharCode(code)) //这里就是转换为字符串
for(var i=0;i<100;i++){
console.log(String.fromCharCode(i)) //小伙伴可以自行打印看看 我这里只取了前100个
}
言归正传,字符串比较的其实就是Unicode编码,像刚才数组怎么排序呢,其实很简单
var arr=['and','Bug','Dog','cat']
arr.sort(function(a,b){
var s=a.toLowerCase()
var t=b.toLowerCase() //都转换大小写比较
if(st){
return 1
}
})
console.log(arr) //(4) ["and", "Bug", "cat", "Dog"]
sort有点啰嗦了,看下一个
concat
Array.concat()创建并返回一个新数组,注意是新数组
var a=[1,2,3]
a.concat(4,5) // [1 2 3 4 5]
a.concat([4,5]) //[1 2 3 4 5]
a.concat([4,5],[6,7]) // [1 2 3 4 5 6 7]
a.concat(4,[5,[6,7]]) // [1 2 3 4 5 [6 7]]
需要注意的是,如果参数是数组,连接的是数组的元素而非数组本身。其次concat不会递归扁平化数组
slice
Array.slice()方法基于当前数组中的一个或多个项创建一个新数组,接受一个或两个参数,最后返回新数组slice(start,end)方法需要两个参数start和end,返回这个数组中从start位置到(但不包含)end位置的一个子数组。左闭右开,就是左边是有等于的而右边没有
如果end为undefined或不存在,则返回从start位置到数组结尾的所有项
如果没有参数,则返回原数组
start和end无法交换位置
如果start是负数,则start = max(length + start,0),也可以理解倒数第几个索引位置
如果end是负数,则end = max(length + end,0),也可以理解倒数第几个索引位置
如果不提供参数,slice()方法返回当前数组的一个浅拷贝
var a=[1,2,3,4,5]
a.slice(0,3) // 1 2 3
a.slice(3) // 4 5
a.slice(1,-1) // 2 3 4 end是负数 其实end此时等于5 + -1 = 4 或者 end是倒数第一个索引位置也就是 4
a.slice(-3,-2) //3 此时其实是 5 + -3 = 2 5 + -2 = 3 倒数第三个数3 索引 2 倒数第二个数字4 索引 3
看自己习惯记忆负数
splice()
Array.splice()可以从数组中删除插入替换元素,最强大的数组方法。与上一个slice看起来相似,slice不改变原数组而splice改变原数组
splice()第一个参数指定了插入和(或)删除的起始位置,第二个参数指定了应该从数组中 删除元素的个数。如果省略第二个参数,从起点到结尾的元素都将删除,splice返回一个由删除元素组成的数组,或者如果没有删除元素就返回一个空数组,注意它会改变原数组
var a=[1,2,3,4,5,6,7,8]
a.splice(4) //返回[5,6,7,8] a变成[1,2,3,4]
a.splice(1,2) //返回[2,3] a是[1,4] 因为会改变原数组 所以此时的a是[1,2,3,4]
a.splice(1,1) //返回[4] a是[1]
注意第二个参数是个数,不是索引,splice也是支持左闭右开的原则
如果我们只操作删除数组,调用前两参数即可,我们来看看插入与替换
var a=[1,2,3,4,5,6,7,8]
a.splice(1,2,'a','b')
console.log(a) // [1, "a", "b", 4, 5, 6, 7, 8] 最简单的替换,删几个 插几个
var a=[1,2,3,4,5,6,7,8]
a.splice(1,0,'a','b')
console.log(a) // [1, "a", "b", 2,3,4, 5, 6, 7, 8] 最简单的插入
push()和 pop()
push()和pop()允许数组当做栈来使用,push()在数组尾部添加一个或多个元素,并返回数组新的长度,注意返回的是长度。pop()方法则相反,删除数组最后一个元素并返回删除的值。虽然改变原数组但返回的值一定要注意一下
简单的方法我就快速过了哈
var a=[1,2]
a.push(3) //3 a[1,2,3]
a.push([4,5]) // 4 a[1,2,3,[4,5]] 传的数组算一项
a.pop() // [4,5] a[1,2,3]
返回什么很重要
unshift()和 shift()
unshift()和shift()的方法类似push()和pop(),unshift()在数组头部添加一个或多个元素,并将已存在的元素移动到更高索引位置,最后返回数组长度。shift()删除数组的第一个元素并返回该元素
找了一个例子偷懒 很舒服
ES5中数组增加了些许方法,我也为大家整理一下
位置方法----indexOf() lastIndexOf()
两者方法都是寻找数组中的元素,返回找到的第一个元素的索引或者没找到返回-1。indexOf()从头至尾搜索,lastIndexOf()反向搜索
a=[0,1,2,1,0]
a.indexOf(1) // 1 正开始数 第1个索引就找到
a.lastIndexOf(1) //3 从后面开始数,第三个索引才找到
a.indexOf(3) //-1 找不着
迭代方法
首先迭代方法的参数有两个,第一个参数是一个函数,函数里面有三个参数,分别是value值,index索引,arr数组本身,第二个参数是this指向 待会看forEach()方法演示
every( )
every()对数组中的每一项运行给定函数,如果该函数对每一项都返回 true ,则返回 true 。 类似于&&符号
var arr=[100,200,300,400,500];
var result=arr.every(function(v){
return v>=100;
});
console.log(result); //true 全部满足才为true
some()
some()就很随便了,其中一项满足就是true
var arr=[100,200,300,400,500];
var result=arr.some(function(v){
return v>=500;
});
console.log(result) //true
filter()
filter()方法,过滤操作,返回满足条件的值
var arr=[100,200,300,400,500];
var result=arr.filter(function(v){
return v>100;
});
console.log(result);// [200, 300, 400, 500]
map()
map()对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。返回就是数组,不考虑true或者false;
var arr=[100,200,300,400,500];
var result=arr.map(function(v){
return v+=v*0.3;
});
console.log(result);//[130, 260, 390, 520, 650]
forEach()
forEach() :对数组中的每一项运行给定函数。这个方法没有返回值。
var arr=[100,200,300,400,500];
arr.forEach(function(a,b,c){//第一个参数:是函数,里面又有三个参数,参1:数组项的值 参2:索引 参3:数组本身
//alert(this);//hehe
console.log(a+'-----'+b+'-----'+c); //可以自行打印看看
},'hehe');//第二个参数使用来改变this指向的
归并方法,一个是reduce()和reduceRight(),这个表示用的很少,我几乎没用过,有兴趣可以自行了解详细的介绍,可能是我太菜了
数组去重
数组去重有很多方法,百度上也有很多,我写一个最原理的方法解析方便记忆,有兴趣的可以自行查找一下,并不是我懒得写,而是......好吧我就是懒,不过掌握好了原理就很简单
var arr=[1,2,1,2,4,5,3,2,1,4,5,7,8] //待去重数组
var newarr=[] //空数组
for(var i=0;i
var arr=[1,2,1,2,4,5,3,2,1,4,5,7,8]
var newarr=[]
for(var i=0;i
数组去重的原理就是前面与后面相对比,做出相应的操作
var arr=[1,2,1,2,4,5,3,2,1,4,5,7,8]
var newarr=arr.filter(function(v,i,arr){
return arr.indexOf(v)==i //每一个索引对应一个值,如果相同的值对应不同的索引那就是重复了
//比如说第一个数字是1 它的索引是0 相对应 可是后面又来了一个1 但是此时它的索引是2 这就不对了
})
console.log(newarr) //[1, 2, 4, 5, 3, 7, 8]
数组排序
有兴趣的小伙伴复制粘贴自行了解一下即可