编辑注:这篇文章讲到数组的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 等等方法 . 好用的很. 由于其他几个方法 都是类似的. 所以 一并写出来了!