JS对象类型-数组方法篇
继承方法
继承自对象的方法有三种:toString()、toLocaleString()和valueOf()
toString()
toString()方法返回数组中元素以逗号分隔的字符串。同不传参的join()方法表现效果一样。
[1,2,3].toString() // '1,2,3'
[1,2,3].join() // '1,2,3'
toLocaleString()
toLocaleString()方法是toString()方法的本地化版本,经常返回相同的值。
[1,2,3].toLocaleString() // '1,2,3'
如果某一项值是null
或undefined
,那么使用toLocaleString()或toString()方法返回值以空字符表示
[1,null,undefined, 2].toString() // '1,,,2'
[1,null,undefined, 2].toLocaleString() // '1,,,2'
valueOf()
valueOf()方法返回数组本身
[1,2,3].valueOf() // [1,2,3]
转换方法
join()方法把数组转换为字符串,它是String.split()
方法的逆向操作,split()是将字符串切割成数组。
join()方法接受一个参数,表示用作分隔符的字符串。
// 默认使用逗号分隔符
[1,2,3].join() // '1,2,3'
// 不使用分隔符
[1,2,3].join('') // '123'
// 空格作为分隔符
[1,2,3].join(' ') // '1 2 3'
实现字符串重复效果
function repeatString(str, n) {
return new Array(n + 1).join(str)
}
repeatString('hi', 3) // 'hihihi'
类数组对象也可以使用join()方法
var arrLike = {0: 'a', 1: 'b', 2: 'c', length: 3}
Array.prototype.join.call(arrLike, '-') // 'a-b-c'
栈和队列方法
栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构,最新添加的项会最先被移除。栈中项的插入(又称推入)和移除(又称弹出)均发生在栈的顶部。JS提供了push()和pop()方法实现了类似栈的行为。
队列是一种FIFO(First-In-First-Out,先进先出)的数据结构,最先添加的项最先被移除。队列中项的插入和移除均发生在列表的底部。JS提供了unshift()和shift()方法实现了类似队列的行为。
push()
push()方法接收任何数量的参数,把它们添加到数组的末尾,返回修改后的数组长度。该操作改变原始数组。
var a = []
console.log(a, a.push('a','b','c')) // ['a','b','c'] 3
console.log(a, a.push(['d','e'])) // ['a','b','c',['d','e']] 4
push()方法也可以向对象中添加元素,对象会变成类数组对象。
var o = {name: 'hello'}
console.log(o, [].push.call(o, 'a', 'b')) // {0: "a", 1: "b", name: "hello", length: 2}
pop()
pop()方法从数组末尾移除最后一项,返回移除项。该操作改变原始数组。
var a = ['a', 'b', 'c']
console.log(a,a.pop()); // ['a', 'b'] 'c'
var a2 = []
console.log(a2,a2.pop()) // [] undefined
unshift()
unshift()方法接收任何数量的参数,把它们添加到数组的前端,返回修改后的数组长度。该操作改变原始数组。
var a = ['a', 'b', 'c']
console.log(a,a.unshift('x','y','z')) //['x','y','z','a', 'b', 'c'] 6
当有多个参数时,参数是一次向插入的,所以插入元素的顺序和参数的顺序一致。
shift()
shift()方法移除数组中的第一项,返回移除项。该操作改变原始数组。
var a = ['a','b','c']
console.log(a,a.shift()); // ['b', 'c'] 'a'
var a2 = []
console.log(a2,a2.shift()) // [] undefined
排序方法
数组中有sort()和reverse()两个排序方法,它们均改变原始数组
reverse()
reverse()方法反转原始数组的顺序,返回排序后的数组。
var arr = [1,2,3]
console.log(arr,arr.reverse()) // [3,2,1] [3,2,1]
sort()
sort()方法默认情况下按字符串升序排列数组项,每个数组项会调用toString()方法,通过比较得到的字符串进行排序,返回排序后的数组。
var a = [1,4,2,3]
console.log(a, a.sort()) // [1,2,3,4]
sort()方法接收一个函数作为参数,可以指定哪个值在哪个值前。函数接收两个参数,如果第一个参数应该位于第二个参数之前则返回一个负数,如果两个参数相等则返回0,如果第一个参数应该位于第二个参数之后则返回一个正数。
function compare(value1,value2){
// 字符串比较需要统一大小写,这里统一小写
var v1 = value1.toLowerCase();
var v2 = value2.toLowerCase();
if(v1 < v2){
return -1;
}else if(v1 > v2){
return 1;
}else{
return 0;
}
}
var arr = ['pig','Cat','dog'];
console.log(arr.sort(compare)); // ["Cat", "dog", "pig"]
数值类型或valueOf()方法返回数值类型的对象类型,可以简化比较函数
function compare(value1,value2){
return value1 - value2;
}
var arr = [5,1,3];
console.log(arr.sort()); // [1, 3, 5]
拼接方法
concat()方法可以接收任意个数参数,它会把参数添加到数组的末尾。如果参数是数组,它会把数组中的每一项添加到数组的末尾。该操作创建一个数组的副本,所以不会改变原始数组。
var a =[1,2,3]
console.log(a,a.concat(4,[5,6], [[7,8]])) // [1, 2, 3] [1, 2, 3, 4, 5, 6, [7,8]]
如果不传递参数则返回一个数组的浅拷贝。
浅拷贝是指如果数组中包含复合类型值(如对象、数组),那么新数组拷贝的是该值的引用。
var a = [1,2]
var newArr = a.concat()
console.log(a,newArr) // [1,2] [1,2]
a[0] = 0
console.log(a,newArr) // [0,2] [1,2]
var a2 = [1, {num: 2}]
var newArr2 = a2.concat()
console.log(a2,newArr2) // [1, {num: 2}] [1, {num: 2}]
a2[1].num = 3
console.log(a2,newArr2) // [1, {num: 3}] [1, {num: 3}]
concat()也可用于对象,把对象合并成数组
var o = {name: 'hello', age: 10}
console.log([].concat.call(o)) // [{name: "hello", age: 10}]
创建子数组
slice(start[,end])接收两个参数,返回字符串从start位置(不包括start位置处的字符)到end位置的一个子数组。如果end不存在,则end等于数组的长度值;如果start或end大于数组的长度,则start或end等于数组的长度。该操作不改变原始数组。
如果start是负数,start = arr.length + start
如果end是负数,end = arr.length + end
var arr = [1,2,3,4,5]
// 没有参数,返回原数组的浅拷贝
arr.slice() // [1,2,3,4,5]
arr.slice(2, 4) // [3,4]
arr.slice(-2) // [4,5]
slice()方法可用于类数组对象,把它变成数组
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })// ['a', 'b']
数组删改
splice()方法可以删改数组中的元素,并且可以在指定位置插入新的元素。该操作会改变原始数组。
splice()方法的第一个参数start表示删除操作的起始位置,当值为负数时start等于length + start。第二个参数表示删除元素的个数,当值为负数时相当于0,值是0时不会删除元素。第二个参数之后的更多参数表示要插入到数组中的元素,插入位置由第一个参数决定。最终会返回一个由删除元素组成的数组。
当只有一个参数时,会把数组在指定位置拆分成两个数组。
var a = [1,2,3,4,5]
console.log(a,a.splice()) // [1,2,3,4,5] []
console.log(a,a.splice(3)) // [1,2,3] [4,5]
console.log(a,a.splice(-2)) // [1,2,3] [4,5]
第二个参数表示删除元素的个数
var a = [1,2,3,4,5]
console.log(a,a.splice(3, 1)) // [1,2,3,5] [4]
console.log(a,a.splice(3, 0)) // [1,2,3,4,5] []
第三个以及之后更多参数都表示要添加的项
var a = [1,2,3,4,5]
console.log(a,a.splice(3, 0,'a','b')) // [1, 2, 3, "a", "b", 4, 5] []
console.log(a,a.splice(3, 2,'a','b')) // [1, 2, 3, "a", "b"] [4,5]
位置查询方法
ES5为数组实例增加了indexOf()和lastIndexOf()两个查询方法,
indexOf()
indexOf(search, start)方法接收两个参数,search表示搜索项,内部使用恒等运算符===
进行比较。start表示搜索的起始位置,会自动调用Number()转型函数,当值为负数时start=length+start。该方法返回search首次出现的位置,如果找不到则返回-1。
var arr = ['a','b','c','b','d']
console.log(arr.indexOf('b')) // 1 a处(包含a)开始搜索
console.log(arr.indexOf('b', 2)) // 3 c处(包含c)开始搜索
console.log(arr.indexOf('b', -2)) // 3 第二个b处(包含b)开始搜索 5 + (-2) = 3
console.log(arr.indexOf('e')) // -1
lastIndexOf()
lastIndexOf(search, start)方法同indexOf()方法类似,不同的是该方法是从右至左执行查询。
var arr = ['a','b','c','b','d']
console.log(arr.lastIndexOf('b')) // 3 d处(包含d)开始搜索
console.log(arr.lastIndexOf('b', 2)) // 1 c处(包含c)开始搜索
console.log(arr.lastIndexOf('b', -2)) // 3 第二个b处(包含b)开始搜索
console.log(arr.lastIndexOf('e')) // -1
注意: 字符串也有indexOf()和lastIndexOf()方法,但是当start为负数时,两则有区别:字符串的这两个方法会把start当做0,而数组的start等于length + start
小技巧: 返回满足条件的所有索引项
function allIndexOf(array,value){
var result = [];
var pos = array.indexOf(value);
if(pos === -1){
return -1;
}
while(pos > -1){
result.push(pos);
pos = array.indexOf(value,pos+1);
}
return result;
}
var array = ['a','b','c','b','d'];
console.log(allIndexOf(array,'b'));//[1,3]
数组归并
数组归并有reduce()和reduceRight()两个方法,它们均接受两个参数:第一个参数是函数,表示如何归并数组元素,它的任务就是使用某种方式把两个值组合成一个值,并返回组合后的值;第二个参数是可选的,表示传递给函数的初始化值。
第一个参数是函数,函数有四个参数,前两个必选,后两个可选:
- 初始变量,默认为数组的第一个元素。函数执行一次后的返回值作为第二次执行的初始化变量,以此类推。
- 当前变量
- 当前变量在数组中的索引
- 原始数组对象
values.reduce(function(prev, cur, index, array){
//todo
});
第二个参数是传递给函数的初始化值。
var a = [1,2,3]
// 求和
var sum = a.reduce(function(prev, cur){ return prev + cur }, 0)
// 求乘积
var product = a.reduce(function(prev, cur){ return prev * cur }, 1)
// 求最大值
var max = a.reduce(function(prev, cur){ return (prev > cur) ? prev : cur })
console.log(sum) // 6
console.log(product) // 6
console.log(max) // 3
第二个参数的类型可以决定函数返回值的类型
var a = [1,2,3]
var sum = a.reduce(function(prev, cur){
prev.sum = prev.sum + cur
return prev
}, {sum: 0})
console.log(sum) // {sum: 6}
注意: 在空数组上使用reduce()方法,如果没有初始化参数的话会导致类型错误。当数组只有一个值且没有初始化参数,或者数组为空且有一个初始化参数时,reduce()方法只会返回那个值而不会调用函数。
var a = []
var sum = a.reduce(function(prev, cur){ return prev + cur }) // 报错
var sum2 = a.reduce(function(prev, cur){ return prev + cur }, 0) // 0
var a2 = [0]
var sum3 = a2.reduce(function(prev, cur){ return prev + cur }) // 0
应用:找出数组中最长的元素
var a = ['a', '123', 'ab', 'hello']
var maxEle = a.reduce(function(prev, cur){
return prev.length > cur.length ? prev : cur
}, '')
console.log(maxEle) // 'hello'
应用:二维数组合并
var a = [['a','b'], ['c','d']]
var arr = a.reduce(function(prev, cur){
return prev.concat(cur)
})
console.log(arr) // ["a", "b", "c", "d"]
reduceRight()方法和reduce()方法类似,不同的是该方法是从高到低(右到左)处理数组。
var a = [1,2,3]
var sum = a.reduceRight(function(prev,cur){
console.log(prev,cur)
return prev + cur
})
console.log(sum)
// 3 2
// 5 1
// 6
迭代方法
ES5为数组定义了5个迭代方法,每个方法都接收两个参数:第一个参数表示要在每一项上运行的函数;第二个参数是可选的,表示运行该函数的作用域对象,用于改变this值。第一个参数中的函数接收三个参数:数组项的值、该项的索引和数组对象本身。
map()
map()方法对数组中的每一项运行指定函数,最终返回一个由函数调用结果组成的数组
var ret = [1,2,3].map(function(item, index, array) {
return item * item
})
console.log(ret) // [1,4,9]
// 第二个参数改变this指向
var arr = ['a','b','c']
var ret2 = [1,2].map(function(item, index, array){
return this[item]
}, arr)
console.log(ret2) // ['b','c']
日常开发中,该方法常用于获取对象数组中的指定属性
var data = [{name: 'li', age: 10}, {name: 'wang', age: 15}, {name: 'zhang', age: 5}]
var ret3 = data.map(function(item, index, array) {
return item.name
})
console.log(ret3) // ["li", "wang", "zhang"]
可以应用于类数组对象
var str = 'hello'
var ret = Array.prototype.map.call(str, function(item, index, arr) {
return item.toUpperCase()
})
console.log(ret) // ["H", "E", "L", "L", "O"]
稀疏数组中不存在的元素,不会调用该方法
var arr = [1,,3]
var ret = arr.map(function(item, index, arr){
return item * 2
})
console.log(ret) // [2, empty, 6]
forEach()
forEach()方法对数组中的每一项运行指定函数,没有返回值。同使用for循环迭代数组效果一样。
[1,2,3].forEach(function(item,index,arr){
console.log(item)
})
// 1
// 2
// 3
var arr = []
[1,2,3].forEach(function(item, index, arr){
this.push(item * item)
}, arr)
console.log(arr) // [1,4,9]
对于多层嵌套的情况,this指向通常不一致,这时第二个参数很有用
var obj = {
name: 'wang',
likes: ['音乐', '编程', '阅读'],
test: function() {
this.likes.forEach(function(item, index, arr){
console.log(item)
}, this)
}
}
console.log(obj.test())
// 音乐
// 编程
// 阅读
forEach()循环可以用于类数组对象
var str = 'abc'
Array.prototype.forEach.call(str, function(item, index, array) {
console.log(item)
})
//a
//b
//c
对于稀疏数组中不存在的元素,forEach()方法不会调用该方法,而for循环照样遍历。
var arr = [1,,3]
for(var i = 0; i < arr.length; i++){
console.log(arr[i])
}
// 1
// undefined
// 3
arr.forEach(function(item, index, arr){
console.log(item)
})
// 1
// 3
forEach()方法无法像for循环一样,在遍历过程中使用break语句终止遍历,会导致发生错误。
var arr = [1,2,3]
arr.forEach(function(item, index, arr){
if(item === 2) break;
})
// Uncaught SyntaxError: Illegal break statement at Array.forEach
filter()
filter()方法对数组中的每一项运行指定函数,返回结果为true的项组成的数组。常用于筛选符合条件的数组项
[1, 2, 3, 4, 5].filter(function (item, index, arr) {
return item % 2 === 0
}) // [2,4]
var min = [3];
var ret = [1, 2, 3, 4, 5].filter(function (item, index, arr) {
return item > this[0]
}, min);//
console.log(ret) // [4,5]
稀疏数组中的空元素会被过滤掉。
// 删除空缺、undefined和null元素
var arr = [1,2,,3,undefined,null]
var ret = arr.filter(function(item, index, arr){
return item != undefined
})
console.log(ret) // [1,2,3]
some()
some()方法对数组中每一项运行指定函数,返回一个布尔值。当每项的执行结果都是false时才返回false,否则返回true。
var arr = [1,2,3]
arr.some(function(item, index, arr){
return item > 2
})
// true
every()
every()方法对数组中每一项运行指定函数,返回一个布尔值。当每项的执行结果都是true时才返回true,否则返回false。
var arr = [1,2,3]
arr.every(function(item, index, arr){
return item > 2
})
// false
结语
JavaScript中数组的方法是通用的,它们除了应用于数组外还可以应用于类数组对象。上面介绍的方法中除了toString()和toLocaleString()方法外,其他方法都是通用的。
可以改变原始数组的方法有七个:push()、 pup()、 unshift()、 shift()、 sort()、 reverse()、 splice()。