前言:最近学习Vue.js过程中用到了几个很有用但是平时不常见的几个操作数组的方法,这里就总结一下。
为了更方便的对JS中Array的操作,ES5规范在Array的原型上新增了9个方法
Array.prototype.indexOf => 查找元素位置
Array.prototype.lastIndexOf => 查找元素位置
Array.prototype.every
Array.prototype.some => 检测数组中的每一个元素,当callback返回true时就停止遍历,并返回true
Array.prototype.forEach => 数组遍历
Array.prototype.map => map的作用是对原数组进行加工处理后并将其作为一个新数组返回
Array.prototype.filter => 创建一个新的匹配过滤条件的数组。
Array.prototype.reduce
Array.prototype.reduceRight
我个人认为是最有用的,很多开发者都会碰到。
一、 indexOf()
indexOf()方法返回在该数组中第一个找到的元素位置,如果它不存在则返回-1。(ps:类似字符串的indexOf方法)
1) 数组内是字符串或者数字
不使用indexOf时
var arr = ['apple','banana','pear'];
var pos = null;
for(var i=0;i<arr.length;i++){
if(arr[i] == 'pear'){
pos = i;
}
}
console.log(pos); //2
使用indexOf时
console.log(arr.indexOf("pear")); //2
2) 数组里面是json(注意:对象在内存中是有自己的地址的)
例1:
var arrJson = [];
var json = {isChecked:false, title:"aaa"};
arrJson.push(json);
var json = {isChecked:false, title:"bbb"};
arrJson.unshift(json);
arrJson.push(
{
isChecked:false,
title:"ccc"
}
);
console.log(arrJson.indexOf(json)); //0 =>可以找到因为其在内存中地址一样。
console.log(arrJson.indexOf({isChecked:false, title:"ccc"}));//-1
例2:
var person = { name: "Datura" };
var people = [{ name: "Datura" }];
var morePeople = [person];
alert(people.indexOf(person)); //-1
alert(morePeople.indexOf(person)); //0
二、 forEach(callback[thisArg])
forEach是用来替换for循环的。第一个参数是回调函数,是必选参数,第二个参数是一个对象,用来改变callback中的this指向,是可选参数。
例1:
var arr = [1,2,3,4,5,6,7,8,9];
for(var i=0;i<arr.length;i++){
console.log(arr[i]);
}
//
arr.forEach(function (item,index) { //第一个参数是元素,第二个参数是索引
console.log(item);
});
例2:
var arr = ['a','b','c'];
arr.forEach(function(item,index,obj){
console.log(item,index,obj);
})
->
a 0 ["a", "b", "c"]
b 1 ["a", "b", "c"]
c 2 ["a", "b", "c"]
从输出的接口可以看出,callback中传入了3个参数item,index,obj 分别表示当前元素、当前位置、数组对象。再看看使用thisArg的情况
例3:
var obj = {
fn:function(a,b){
console.log(a,b);
}
};
var arr = ['a','b','c'];
arr.forEach(function(v,i,a){
this.fn(v,i);
},obj);
不传thisArgs时,callback中的 this 默认指向window对象,当传递thisArg时,callback中的this就指向了thisArg,因此这个参数的目的就是为了改变回调函数中的this指向。
三、 filter(callback[thisArg])
filter是过滤
的意思,所以这个方法的作用就是返回一个匹配过滤条件的新数组,其接收两个参数callback和thisArg, callback也是回调函数,主要用于对元素进行条件匹配,thisArg和forEach中的thisArg作用一样,在这里就不重复了,看下面.
例1:
var arr = [
{"name":"apple","count":2},
{"name":"banana","count":1},
{"name":"orange","count":3},
{"name":"pear","count":5}
];
var arrNew = [];
for(var i=0;i<arr.length;i++){
if(arr[i].name == 'orange'){
arrNew.push(arr[i]);
}
}
console.log(arrNew);
var arrNew2 = arr.filter(function (item) {
return item.name === "orange";
});
console.log(arrNew2)
例2:
var arr = ["a","b","a","c"];
var newArr = arr.filter(function(item){
return item === "a";
});
newArr -> ["a","a"]
四、 map(callback[thisArg])
map()对数组的每个元素进行一定操作(映射)后,会返回一个新的数组,map()是处理服务器返回数据时是一个非常实用的函数。
例1:
//不使用map
var arrFruit = [
{
"name":"apple",
"count":3
},
{
"name":"banana",
"count":2
},
{
"name":"orange",
"count":4
},
{
"name":"pear",
"count":5
}
];
function getArrNew() {
var arrNew = [];
for(var i=0;i<arrFruit.length;i++){
var item = arrFruit[i];
item.newData = [item.name,item.count].join("剩余");
arrNew[i] = item;
}
return arrNew;
}
console.log(getArrNew());
function getArrNew2() {
return arrFruit.map(function (item,index) {
item.newData = [item.name,item.count].join("剩余");
return item;
});
}
console.log(getArrNew2());
例2:
var arr = [
{w:10,h:10}, //定义长和宽
{w:15,h:20},
{w:12,h:12}
];
var newArr = arr.map(function(item){
//根据长宽计算出面积并赋值给新属性area
item.area = item.w * item.h;
return item;
});
newArr[0] - > {w: 10, h: 10, area: 100}
可以看出,newArr返回的是增加了area属性的对象数组。这个方法非常实用,一般情况下,当一个ajax请求返回时,我们都要对其结果集进行过滤和校验等操作,这时map就派上用场了。我们再看看如果对map进行兼容性扩展:
例3:
if(!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var temp = [];
for (var i = 0; i < this.length; i++) {
var newItem = callback.call(thisArg,this[i]);
temp.push(newItem); //将callback返回的新元素压入temp中
}
return temp;
}
}
五、 reduce(callback[initialValue])
reduce()可以实现一个累加器的功能,将数组的每个值(从左到右)将其降低到一个值。
说实话刚开始理解这句话有点难度,它太抽象了。
场景: 统计一个数组中有多少个不重复的单词 。
例1:
//不使用reduce时
var arr = ["apple","orange","apple","orange","pear","orange"];
function getWordCnt(){
var obj = {};
for(var i=0;i<arr.length;i++){
var item = arr[i];
obj[item] = (obj[item] +1 ) || 1;
}
return obj;
}
// console.log(getWordCnt());
让我先解释一下我自己对reduce的理解。reduce(callback, initialValue)会传入两个变量。回调函数(callback)和初始值(initialValue)。假设函数它有个传入参数,prev和next,index和array。prev和next你是必须要了解的。
一般来讲prev是从数组中第一个元素开始的,next是第二个元素。但是当你传入初始值(initialValue)后,第一个prev将是initivalValue,next将是数组中的第一个元素。
比如
例2:
var arr = ["apple","orange"];
function noPassValue(){
return arr.reduce(function(prev,next){
console.log("prev:",prev);
console.log("next:",next);
return prev + " " +next;
});
}
function passValue(){
return arr.reduce(function(prev,next){
console.log("prev:",prev);
console.log("next:",next);
prev[next] = 1;
return prev;
},{});
}
//console.log(noPassValue());
console.log(passValue());
例3:
var arr = [1,2,3,4];
var newArr = arr.reduce(function(previousValue, currentValue, currentIndex, array){
console.log(previousValue, currentValue,currentIndex);
return previousValue + currentValue;
},100);
100 1 0
101 2 1
103 3 2
106 4 3
newArr -> 110
从运行结果看,initialValue参数指定了previousValue的初始值,更重要的是,这次数组是从第1个位置开始遍历,而不再是从第2个位置开始了。 现在回过头来,对照这两个例子,我相信你一定能够理解reduce的作用了。下面对于reduce的扩展会巩固你对reduce的理解:
例4:
if(!Array.prototype.reduce) {
Array.prototype.reduce = function (callback, initialValue) {
var previousValue = initialValue || this[0];//如果不指定intialValue,则默认为数组的第一个元素
//如果不指定initialValue,i从1开始遍历,否则就从0开始遍历
for (var i = initialValue?0:1; i < this.length; i++) {
//previousValue 累加每一次返回的结果
previousValue += callback(previousValue, this[i],i,this.toString());
}
return previousValue;
}
}
####六、 reduceRight(callback[initialValue])
reduce的作用完全相同,唯一的不同是,reduceRight是从右至左遍历数组的元素。
####七、 some(callback[thisArg])
ome是`某些、一些`的意思,因此,some的作用是检测数组中的每一个元素,当callback返回true时就停止遍历,并返回true,这样的描述似乎有些抽象,看代码,一切尽在代码中:
**例1:**
var arr = [ 1, 2, 3, 4];
var result = arr.some( function( item, index, array ){
console.log( item, index, array);
return item > 2;
});
->
1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]
restule -> true
从运行结果看,some检测整个数组,只要当arr中有一个元素符合条件item>2 就停止检测和遍历,并返回true,以表示检测到目标。这和我们在for循环中使用break语言的作用有点类似,这会儿你应该明白some的作用了吧! 下面对于some的扩展会有助于你对some的理解:
**例2:**
if(!Array.prototype.some) {
Array.prototype.some = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if(callback.call(thisArg,this[i],i,this.toString())){
return true; //检测到callback返回true,跳出循环,并返回true
}
}
return false; //一个符合条件的都没有检测到,返回false
}
}
####八、 every(callback[thisArg])
every是`每一个`的意思,相比some来讲,every对元素的检测应该更加严格,那every到底是干什么的呢,看代码就知道了:
**例1:**
var arr = [ 1, 2, 3, 4];
var result = arr.every( function( item, index, array ){
console.log( item, index, array );
return item < 3;
});
1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]
result -> false
从运行结果看,当检测第3个元素时,item<2为false, 停止检测,并返回false, 这说明every在检测元素时,要求每一个元素都要符合条件item<3,如果有一个不符合就停止检测,并返回false,(ps:你可以测试item<5时的运行结果,返回值一定是true). 那every到底有什么用武之地呢? 当一个for循环使用了break语句后,我们想知道for循环是否正常的执行完时, 我们一般会通过检测for中的索引i==arr.length来判断,因此every的作用就体现在这里。 我们再看看对于every的扩展:
**例2:**
if(!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if(!callback.call(thisArg,this[i],i,this.toString())){
return false; //检测到不符合条件的元素,跳出循环,并返回false
}
}
return true; //所有元素都符合条件,返回true
}
}
####九. forEach 与map的区别:
高级浏览器支持forEach方法
语法:forEach和map都支持2个参数:一个是回调函数(item,index,list)和上下文;
forEach:用来遍历数组中的每一项;这个方法执行是没有返回值的,对原来数组也没有影响;
数组中有几项,那么传递进去的匿名回调函数就需要执行几次;
每一次执行匿名函数的时候,还给其传递了三个参数值:数组中的当前项item,当前项的索引index,原始数组input;
理论上这个方法是没有返回值的,仅仅是遍历数组中的每一项,不对原来数组进行修改;但是我们可以自己通过数组的索引来修改原来的数组;
forEach方法中的this是ary,匿名回调函数中的this默认是window;
**例1:**
var ary = [12,23,24,42,1];
var res = ary.forEach(function (item,index,input) {
input[index] = item*10;
})
console.log(res);//-->undefined;
console.log(ary);//-->会对原来的数组产生改变;
map: 和forEach非常相似,都是用来遍历数组中的每一项值的,用来遍历数组中的每一项;
区别:map的回调函数中支持return返回值;return的是啥,相当于把数组中的这一项变为啥(并不影响原来的数组,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了);
不管是forEach还是map 都支持第二个参数值,第二个参数的意思是把匿名回调函数中的this进行修改。
**例2:**
var ary = [12,23,24,42,1];
var res = ary.map(function (item,index,input) {
return item*10;
})
console.log(res);//-->[120,230,240,420,10];
console.log(ary);//-->[12,23,24,42,1];
[完...]()