前言:最近學習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];
[完...]()