js數組之indexOf/filter/forEach/map/reduce詳解

編輯注:這篇文章講到數組的5個使用方法,目前我比較常用的有indexOf和forEach,其它則很少見,這些屬性熟記于心能夠給你平時的編碼帶來意想不到的方便,有點可惜的是在IE9以下都不支持這些方法,不過如果你是在移動端和現代瀏覽器上則不需要考慮這些兼容,另外微信小程序也支持這種寫法。 在ES5中,一共有9個Array方法 http://kangax.github.io/compat-table/es5/ 注* 九個方法

Array.prototype.indexOf
Array.prototype.lastIndexOf
Array.prototype.every
Array.prototype.some
Array.prototype.forEach
Array.prototype.map
Array.prototype.filter
Array.prototype.reduce
Array.prototype.reduceRight
我將挑選5種方法,我個人認為是最有用的,很多開發者都會碰到。

1) indexOf

indexOf()方法返回在該數組中第一個找到的元素位置,如果它不存在則返回-1。 不使用indexOf時
var arr = ['apple','orange','pear'],
found = false;

for(var i= 0, l = arr.length; i< l; i++){
if(arr[i] === 'orange'){
found = true;
}
}

console.log("found:",found);
使用后
var arr = ['apple','orange','pear'];

console.log("found:", arr.indexOf("orange") != -1);

2) filter

該filter()方法創建一個新的匹配過濾條件的數組。 不用 filter() 時
var arr = [
{"name":"apple", "count": 2},
{"name":"orange", "count": 5},
{"name":"pear", "count": 3},
{"name":"orange", "count": 16},
];

var newArr = [];

for(var i= 0, l = arr.length; i< l; i++){
if(arr[i].name === "orange" ){
newArr.push(arr[i]);
}
}

console.log("Filter results:",newArr);
用了 filter():
var arr = [
{"name":"apple", "count": 2},
{"name":"orange", "count": 5},
{"name":"pear", "count": 3},
{"name":"orange", "count": 16},
];

var newArr = arr.filter(function(item){
return item.name === "orange";
});


console.log("Filter results:",newArr);

3) forEach()

forEach為每個元素執行對應的方法
var arr = [1,2,3,4,5,6,7,8];

// Uses the usual "for" loop to iterate
for(var i= 0, l = arr.length; i< l; i++){
console.log(arr[i]);
}

console.log("========================");

//Uses forEach to iterate
arr.forEach(function(item,index){
console.log(item);
});
forEach是用來替換for循環的

4) map()

map()對數組的每個元素進行一定操作(映射)后,會返回一個新的數組, 不使用map
var oldArr = [{first_name:"Colin",last_name:"Toh"},{first_name:"Addy",last_name:"Osmani"},{first_name:"Yehuda",last_name:"Katz"}];

function getNewArr(){

var newArr = [];

for(var i= 0, l = oldArr.length; i< l; i++){
var item = oldArr[i];
item.full_name = [item.first_name,item.last_name].join(" ");
newArr[i] = item;
}

return newArr;
}

console.log(getNewArr());
使用map后
var oldArr = [{first_name:"Colin",last_name:"Toh"},{first_name:"Addy",last_name:"Osmani"},{first_name:"Yehuda",last_name:"Katz"}];

function getNewArr(){

return oldArr.map(function(item,index){
item.full_name = [item.first_name,item.last_name].join(" ");
return item;
});

}

console.log(getNewArr());
map()是處理服務器返回數據時是一個非常實用的函數。

5) reduce()

reduce()可以實現一個累加器的功能,將數組的每個值(從左到右)將其降低到一個值。 說實話剛開始理解這句話有點難度,它太抽象了。 場景: 統計一個數組中有多少個不重復的單詞 不使用reduce時
var arr = ["apple","orange","apple","orange","pear","orange"];

function getWordCnt(){
var obj = {};

for(var i= 0, l = arr.length; i< l; i++){
var item = arr[i];
obj[item] = (obj[item] +1 ) || 1;
}

return obj;
}

console.log(getWordCnt());
使用reduce()后
var arr = ["apple","orange","apple","orange","pear","orange"];

function getWordCnt(){
return arr.reduce(function(prev,next){
prev[next] = (prev[next] + 1) || 1;
return prev;
},{});
}

console.log(getWordCnt());
讓我先解釋一下我自己對reduce的理解。reduce(callback, initialValue)會傳入兩個變量?;卣{函數(callback)和初始值(initialValue)。假設函數它有個傳入參數,prev和next,index和array。prev和next你是必須要了解的。 一般來講prev是從數組中第一個元素開始的,next是第二個元素。但是當你傳入初始值(initialValue)后,第一個prev將是initivalValue,next將是數組中的第一個元素。 比如:
/*
* 二者的區別,在console中運行一下即可知曉
*/

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("No Additional parameter:",noPassValue());
console.log("----------------");
console.log("With {} as an additional parameter:",passValue());
原文地址: colintoh.com 如何兼容IE瀏覽器,看看這篇:讓ie以及老版本w3c瀏覽器 也支持ES5的 數組對象的 幾個新增方法. 寫了簡單注釋. 具體用法 請參考 ES5 手冊 .
// 模擬ES5 Array.prototype.forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(f, oThis) {
if (!f || f.constructor != Function.toString()) return;
oThis = oThis || window;
for (var i = 0, len = this.length; i < len; i++) {
f.call(oThis, this[i], i, this); //p1 上下文環境 p2 數組元素 p3 索引 p4 數組對象
}
}
}
//模擬 ES5 Array.prototype.filter
if (!Array.prototype.filter) {
Array.prototype.filter = function(f, oThis) {
if (!f || f.constructor != Function.toString()) return;
oThis = oThis || window;
var a = [];
for (var i = 0, len = this.length; i < len; i++) {
if (f.call(oThis, this[i], i, this)) a.push(this[i]);
}
return a;
}
}
//模擬 ES5 Array.prototype.map
if (!Array.prototype.map) {
Array.prototype.map = function(f, oThis) {
if (!f || f.constructor != Function.toString()) return;
oThis = oThis || window;
var a = [];
for (var i = 0, len = this.length; i < len; i++) {
a.push(f.call(oThis, this[i], i, this));
}
return a;
}
}
//模擬 ES5 Array.prototype.every
if (!Array.prototype.every) {
Array.prototype.every = function(f, oThis) {
if (!f || f.constructor != Function.toString()) return;
oThis = oThis || window;
for (var i = 0, len = this.length; i < len; i++) {
if (!f.call(oThis, this[i], i, this)) return false;
}
return true;
}
}
//模擬 ES5 Array.prototype.some
if (!Array.prototype.some) {
Array.prototype.some = function(f, oThis) {
if (!f || f.constructor != Function.toString()) return;
oThis = oThis || window;
for (var i = 0, len = this.length; i < len; i++) {
if (f.call(oThis, this[i], i, this)) return true;
}
return false;
}
}
要重點說一說的 indexOf lastIndexOf 兩個方法 .. 我只是實現了一個簡單版本.但修復了 一點點小問題 . 先看代碼
//模擬 ES5 Array.prototype.indexOf方法.并修復ff等其他實現 indexOf方法的瀏覽器中值類型于引用類型比較相等性一律返回false問題
Array.prototype.indexOf = function(obj) {
for (var i = 0, len = this.length; i < len; i++) {
if (compare(this[i], obj)) return i;
}
return -1;
}
//模擬 ES5 Array.prototype.lastIndexOf方法.并修復ff等其他實現 indexOf方法的瀏覽器中值類型于引用類型比較相等性一律返回false問題
Array.prototype.lastIndexOf = function(obj) {
for (var i = this.length - 1; i >= 0; i--) {
if (compare(this[i], obj)) return i;
}
return -1;
}
是的. 注釋已經寫的明白.? 我這里之所以 用這個方法 覆蓋了 ES5 的方法原因在于
//比較對象是否于參數obj 相等..
function compare(obj1, obj2) {
if (obj1 == null || obj2 == null) return (obj1 === obj2);
return (obj1 == obj2 && obj1.constructor.toString() == obj2.constructor);
}
這個 compare方法 . 他解決了一個什么問題呢? 對了! 就是相等性判斷. 因為我發現? 原始版本的相等性判斷 居然會認為 1!=new Number(1)? 即 假如數組中存在一個 number對象 而我用 number 直接量去做比較 即使本應該相等. 也會返回false 這于 javascript? 引用類型 于值類型做 相等性運算時? 會調用引用類型 即對象的 valueOf方法 然后再去做比較 是相違背的. 說明 javascript 1.6 在實現 indexOf方法時 相等性判斷 他簡單的用了 === 即嚴格相等判斷 ... 那么我寫的compare 方法 的作用即 解決這個問題. 讓相等性判斷 遵循 javascript的原始規則... 說到這里 不得不提一下? 老外 在判斷 某個對象 為某特定類型時. 會使用 Object.porototyp.toString.call(this) 來做比較. 目的是為了防止 如 [1,2,3].constructor!=iframe.contentWindow.Array 這類情況... 其實大可不必那么麻煩 .? 我們只需要調用 兩邊的構造器對象 的其中一個的toString方法 返回一個?值類型的?string 偽對象即可. 這樣 另外一邊的引用類型 也會 自動調用 valueOf方法 于字符串做比較.. 何必 搞的那么麻煩呢?   最后. 恩 總體來說 我非常喜歡 forEach? map filter 等等方法 . 好用的很. 由于其他幾個方法 都是類似的. 所以 一并寫出來了!