基本语法
声明数组:
let arr = ['第一','第二','第三']//orlet arr = new Array('第一','第二','第三')
第一个就可以了。
数组从0开始,通过下标指定想要获取数组里面的值:
arr[0] //'第一'arr[1] //'第二'arr[2] //'第三'
可通过下标指定的值,替换内容,如:
arr[0] = "修改了第一的内容"console.log(arr) // ["修改了第一的内容",'第二','第三']
也可以自己在数组后面手动添加内容,例如:
arr[3] = "自己添加了第四"console.log(arr) // ["修改了第一的内容",'第二','第三',"自己添加了第四"]
当然,数组有 length 得出数组的值:
console.log(arr.length) // 4
数组的内容可以是任何类型:
let arr = ['第一', {name: 'John'}, true, function(){consoel.log('hellow')}]consoel.log(arr[1].name) //"John"arr[3]() //'hellow'
数组方法
pop/push
pop方法是把数组末端最后的元素取出来并返回,如:
let arr = ['第一','第二','第三']arr.pop() // '第三'console.log(arr) // ['第一','第二']
push与pop相反,在数组末端添加一新元素:
let arr = ['第一','第二','第三']arr.pop("添加第四")console.log(arr) // ['第一','第二','第三',"添加第四"]
shift/unshift
与上面的类似,只不过专门针对数组首端
shift方法,把数组的第一个元素取出来并返回, 并且后面的元素就会往前排,例如原本下标为1的元素就变成下标为0 :
let arr = ['第一','第二','第三']console.log(arr[0]) // '第一'arr.shift() // '第一'console.log(arr) // ['第二','第三']console.log(arr[0]) // '第二'
unshift方法,类似的,在首端前面新增一个元素,后面的元素就需要往后排:
let arr = ['第一','第二','第三']console.log(arr[0]) // '第一'arr.unshift('新增一个第一') // '第一'console.log(arr) // ['新增一个第一','第一','第二','第三']console.log(arr[1]) // '第一'
上面四种方法,允许开发者在一个数组的前后两端进行新增、删除操作,就类似于栈,遵循“先进后出”原则,在计算机科学里,这样的数据结构称之为“双端队列”。
性能
以上四种方法是有性能区别的, push 和 pop 性能比 shift 和 unshift 快。元素越多,该性能区别越明显。
因为shift 和 unshift 对数组的前端操作,每操作一次,后面的数组的下标就要变化一次,元素越多,所花的时间就越多。
数组的特殊之处
在JS中,只有8种原始类型,分别是:Number,String、Boolean、Bight、null、undefined、symbol、object。并没有数组类型,也就是说,JS的数组是一个特殊的对象。即object类型!
也就是说,数组可以像对象一样使用,甚至还可以如下:
let arr = ['第一','第二','第三']arr[9999] = 'a' //分配索引值远大于原数组的长度的属性,中间什么都没有arr[8888] = 'b' //倒序填充属性arr.name = '小名' //像对象一样给数组一个属性
以上就不要用了,像正常的数组对待即可。
遍历数组
最原始的遍历就是直接使用 for 语句:
let arr = [1,2,3]for (let i = 0; i < arr.length; i++){console.log(arr[i])}
还有一种遍历方法,使用 for...fo :
let arr = [1,2,3]for(let arr of arrs){console.log(arr)}
因为数组也是对象,所以可以使用 for...in :
let arrs = [1,2,3]for(let key in arrs){console.log(arrs[key])}
但是该方法存在一定的危险,for...in 语句会遍历所有的属性,因为数组是对象,该语句会遍历length和索引属性。所以在数组建议不使用for...in 语句,而是使用for...fo ,普通对象就可以使用for...in 。
数组方法进阶
除了以上提到的4个方法,还有其他的方法。
splice
多功能瑞士刀,功能兼具以上方法,也就是可以增加、删除、插入。语法:
let arrs = [1,2,3]arrs.splice(state[, deleteCount, elem1,...,elemN])
start 指的是arr的下标,往后开始修改。 deleteCount ,删除N个元素并插入 elem1,...,elemN ,然后返回已经被删除的元素。例如:
arrs.splice(1,1,'小明') //返回已经删除的[2]console.log(arrs) //[1,'小明',3]//orlet arr = arrs.splice(1,1,'小明','小红')console.log(arr) //[2]console.log(arrs) //[1,'小明','小红',3]
slice
复制数组到一个新的数组。
语法:
arr.slice(start, end)
返回一个数组,将从start到end(不包括end)的数组复制到一个新的数组。如:
let arrs = [1,2,3]let arr1 = arrs.slice(0,2)console.log(arr1) //[1,2]//也可以let arr1 = arrs.slice() //全部复制
concat
创建一个新数组,其中包括来自其他数组和其他项的值。
语法:
arr.concat(arg1, arg2, ...,argN)
如:
let arrs = [1,2,3]let arrs1 = ["小明","小红"]let arrx = arrs.concat(arrs1, [3,4,5,6,7,],33,44,55)console.log(arrx) //[1, 2, 3, "小明", "小红", 3, 4, 5, 6, 7, 33, 44, 55]
forEach
为数组里面的每个元素都运行一个函数:
如:
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => {console.log(`${item} is at index ${index} in ${array}`)});

数组搜索
在数组中搜索想要的元素,有几种方法。
indexOf、lastIndexOf、includes
indexOf(item,from)从索引from开始搜索item,找到返回索引,没有返回-1。lastIndexOf(item, from)作用同上,只是从右往左的去查找。includes(item, from)作用一样,但查找的时候如果有,返回true,反之返回false
例如:
let arr = [1, 0, false]console.log(arr.index(0)) //1console.log(arr.index(false)) //2console.log(arr.index(null)) //-1console.log(arr.includes(1)) //true
注意,includes 可以比较精准的查找到NaN:
const arr = [1,2,3,NaN,5]console.log(arr.indexOf(NaN)) //-1console.log(arr.includes(NaN)) // 3
find 与 findIndex
假如有个对象数组,我要怎么查找某个对象里面的元素呢?这里就用到了find。语法如下:
arr.find(function(item, index, array){//如果找到,就会返回true,并停止迭代且返回item//如果没有,则返回undefined})
该方法依次对数组中的每个元素调用该函数:
item是元素index是数组的索引array是数组本身
例如:
let users = [{id: 1, name: '小明'},{id: 2, name: '小红'}]let user = users.find(item => item.id === 1)console.log(user.name) //'小明'
而 findIndex 和 find 是一样的语法,但是如果找到元素,就会返回元素的索引,而不是元素的本身,反之返回-1。
filter
在迭代对象数组时,如果搜索条件为ture的对象,就返回并继续迭代。语法与 find 是一致的,如:
let users = [{id: 1, name: "小明"},{id: 2, name: "小红"},{id: 3, name: "小黄"}];let user = users.filter(item => item.id > 1)console.log(user[0].name) //"小红"
转换数组
map
对数组的每个元素都调用函数,并返回结果数组。语法与 find 一样:
let result = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length)console.log(result) //[5,7,6]
sort
该方法对数组进行原位(即对原数组进行修改)排序,更改数组的顺序,并返回排序后的数组:
let arr = [1,2,15]arr.sort() //如果不传参,就会按照字符串的字典排序,结果如下console.log(arr) //[1,15,2]
传参后:
function compareNumeric(a, b){ //注意,sort这个方法是两两比较的,所以这里也是两个参数if(a > b) return 1;if (a == b) return 0;if (a < b) return -1;}let arr = [1,2,15]arr.sort(compareNumeric)console.log(arr) //[1, 2, 15]
以上的代码可以简化:
let arr = [1,2,15]arr.sort((a,b) => a - b)console.log(arr) //[1, 2, 15]
reverse
该方法可用于颠倒数组中的元素的顺序。例如:
let arr = [1,2,3,4,5,6,7,8]arr.reverse()console.log(arr) // [8, 7, 6, 5, 4, 3, 2, 1]
split 和 join
split 是用于分隔一个字符串,返回数组,如:
let str = 'Bilbo, Gandalf, Nazgul';let arr = str.split(",")console.log(arr) //['Bilbo', 'Gandalf', 'Nazgul']
该方法有个可选项,可以限定长度,如:
let str = 'Bilbo, Gandalf, Nazgul';let arr = str.split(",", 2)console.log(arr) //['Bilbo', 'Gandalf']
如果参数为空字符串,会:
let str = "string"let arr = str.split('')console.log(arr) //["s", "t", "r", "i", "n", "g"]
而 join 相反,把数组的所有元素连接成一个字符串:
let arr = ["s", "t", "r", "i", "n", "g"]let str = arr.join('+')console.log(str) //'s+t+r+i+n+g'
reduce 和 reduceRight
与 forEach 和 map 差不多,也是为数组内的每个元素都执行一次,但是这个用法稍微复杂点。语法如下:
let value = arr.reduce(function(accumulator, item, index, array){// ...}, [initial])
参数讲解:
accumulator:是上一个函数的调用结果,初始化的时候就等于initial(前提提供了initial)item:当前数组的元素。index:当前数组的元素的下标。array:数组本身。initial:初始值,如果不事先设置,则默认把数组的第一个元素当作初始值。
例子:
let result1 = arr.reduce((sum, current, a, b) => {sum + current;console.log(`index: ${a}, arr: ${b}`)}, 0)
结果:
这个运行过程:
- sum(
accumulator)的初始值为initial,而current(item)为遍历的第一个元素,即值为1,所以1+0结果就为1 。 - 上一次的结果为1 ,所以
sum = 1,然后current遍历的第2个元素为2,所以1+2的值为3. - 以此类推。。。。
流程图:
而 reduceRight 如方法名一样,遍历是从右往左,作用一样。
Array.isArray
该方法作用是判断数组是否是数组!
由于数组是基与对象的,所以判断原始类型的 typeof 判断数组的结果只能是对象。如下 :
let arr = []typeof(arr) //"object"Array.isArray(arr) //true
关于数组方法里的this
大多数的方法参数最后是有可选参数的,这个可选参数是 thisArg ,例如:
arr.find(func, thisArg);arr.filter(func, thisArg);arr.map(func, thisArg);//...
而 thisArg 的值就是 func 的 this 。例如:
let army = {minAge: 18,maxAge: 27,canJoin(user){console.log(`minAge:${this.minAge}, maxAge:${this.maxAge}`) //minAge:18, maxAge:17return user.age >= this.minAge && user.age < this.maxAge}}let users = [{age: 16},{age: 19},{age: 26},{age: 32}]let arr = users.filter(army.canJoin, army)console.log(arr[0].age) //16
如果不给 thisArg 参数,那么 this = undefined 。
当然,上面的第15行代码可以换成如下更好理解:
let arr = users.filter(user => army.canJoin(user))
总结
数组添加删除操作:
pop—— 末端最后一个元素被取出并返回push—— 末端添加一个新的元素shift—— 首端第一个元素被取出并返回unshift—— 首端新添加一个新的元素
数组万能操作:
splice(state[,deleteCount, ..., items)—— 从state开始删除deleteCount个元素,并插入items(原位in-place: 对,操作自身的,不会创建新的数) 。slice(state, end)—— 从索引state开始到索引end(不包括end)的元素复制到新的数组。concat(...items)—— 返回一个新的数组,复制当前数组所有元素,并向其中添加items。如果items里也有数组,那么把这个数组里面的元素复制出了。
遍历操作:
forEach(func)—— 为每个元素执行一次函数,可以修改里面的元素,并不会返回任何内容。
数组搜索:
indexOf(from, item) / lastIndex(from, item)—— 从from开始查找数组内是否有想要item,有返回该元素,无返回-1。find(func)—— 为每个元素执行一次函数,如果使得func返回true,就返回这个的值,并停止迭代;没有就返回undefined。findIndex(func)—— 同上,只不过ture只会返回索引下标而不是值。filter(func)—— 与find类似,但如果执行到true就会返回并继续迭代直到结束。
数组转换:
map(func)—— 为数组内的每个元素执行一次函数,与forEach是差不多的,但是这个不会修改数组里面的元素,会返回新的数组。sort(func)—— 对原来的数组进行排序(原位in-place),然后返回。reverse()—— 对原来的数组进行反转,然后返回(也是原位in-place)splite()—— 对字符串进行切割并返回数组。join()—— 对数组进行拼接成字符串。reduce(func[, initial]) / reduceRight(func[, initial])—— 对数组里的每个元素执行一次函数,并把函数的结果传递给下一次的执行。
数组判断:
Array.isArray(arr)判断是否是数组。
