引自:by zhangxinxu from http://www.zhangxinxu.com
ES5中新增了写数组方法,如下:
- forEach (js v1.6)
- map (js v1.6)
- filter (js v1.6)
- some (js v1.6)
- every (js v1.6)
- indexOf (js v1.6)
- lastIndexOf (js v1.6)
- reduce (js v1.8)
- reduceRight (js v1.8)
浏览器支持
- Opera 11+
- Firefox 3.6+
- Safari 5+
- Chrome 8+
- Internet Explorer 9+
1.forEach
显而易见,forEach
方法中的function
回调支持3个参数,第1个是遍历的数组内容;第2个是对应的数组索引,第3个是数组本身。
因此,我们有:
[].forEach(function(value, index, array) { // ... });
对比jQuery中的$.each
方法:
$.each([], function(index, value, array) { // ... });
会发现,第1个和第2个参数正好是相反的.
再下面,更进一步,forEach
除了接受一个必须的回调函数参数,还可以接受一个可选的上下文参数(改变回调函数里面的this
指向)(第2个参数)。
array.forEach(callback,[ thisObject])例子更能说明一切:
var database = { users: ["张含韵", "江一燕", "李小璐"], sendEmail: function (user) { if (this.isValidUser(user)) { console.log("你好," + user); } else { console.log("抱歉,"+ user +",你不是本家人"); } }, isValidUser: function (user) { return /^张/.test(user); } }; // 给每个人法邮件 database.users.forEach( // database.users中人遍历 database.sendEmail, // 发送邮件 database // 使用database代替上面标红的this ); // 结果: // 你好,张含韵 // 抱歉,江一燕,你不是本家人 // 抱歉,李小璐,你不是本家
综上全部规则,我们就可以对IE6-IE8进行仿真扩展了,如下代码:
// 对于古董浏览器,如IE6-IE8 if (typeof Array.prototype.forEach != "function") { Array.prototype.forEach = function (fn, context) { for (var k = 0, length = this.length; k < length; k++) { if (typeof fn === "function" && Object.prototype.hasOwnProperty.call(this, k)) { fn.call(context, this[k], k, this); } } }; }
2.map
map
方法的作用不难理解,“映射”嘛,也就是原数组被“映射”成对应新数组。下面这个例子是数值项求平方:
var data = [1, 2, 3, 4]; var arrayOfSquares = data.map(function (item) { return item * item; }); alert(arrayOfSquares); // 1, 4, 9, 16
注意:callback
需要有return
值
在实际使用的时候,我们可以利用map
方法方便获得对象数组中的特定属性值们。例如下面这个例子(之后的兼容demo也是该例子):
var users = [ {name: "张含韵", "email": "[email protected]"}, {name: "江一燕", "email": "[email protected]"}, {name: "李小璐", "email": "[email protected]"} ]; var emails = users.map(function (user) { return user.email; }); console.log(emails.join(", ")); // [email protected], [email protected], [email protected]
Array.prototype
扩展可以让IE6-IE8浏览器也支持map
方法:
if (typeof Array.prototype.map != "function") { Array.prototype.map = function (fn, context) { var arr = []; if (typeof fn === "function") { for (var k = 0, length = this.length; k < length; k++) { arr.push(fn.call(context, this[k], k, this)); } } return arr; }; }
3.filter
filter
为“过滤”、“筛选”之意。指数组filter
后,返回过滤后的新数组。用法跟map
极为相似:
filter
的callback
函数需要返回布尔值true
或false
. 如果为true
则表示,恭喜你,通过啦!如果为false
, 只能高歌“我只能无情地将你抛弃……”。
var data = [0, 1, 2, 3]; var arrayFilter = data.filter(function(item) { return item; }); console.log(arrayFilter); // [1, 2, 3]
我们在为低版本浏览器扩展时候,无需关心是否返回值是否是纯粹布尔值(见下黑色代码部分):
if (typeof Array.prototype.filter != "function") { Array.prototype.filter = function (fn, context) { var arr = []; if (typeof fn === "function") { for (var k = 0, length = this.length; k < length; k++) { fn.call(context, this[k], k, this) && arr.push(this[k]); } } return arr; }; }
4.some
some
意指“某些”,指是否“某些项”合乎条件。
var scores = [5, 8, 3, 10]; var current = 7; function higherThanCurrent(score) { return score > current; } if (scores.some(higherThanCurrent)) { alert("朕准了!"); }
结果弹出了“朕准了”文字。 some
要求至少有1个值让callback
返回true
就可以了。显然,8 > 7
,因此scores.some(higherThanCurrent)
值为true
.
我们自然可以使用forEach
进行判断,不过,相比some
, 不足在于,some
只有有true
即返回不再执行了。
IE6-IE8扩展如下:
if (typeof Array.prototype.some != "function") { Array.prototype.some = function (fn, context) { var passed = false; if (typeof fn === "function") { for (var k = 0, length = this.length; k < length; k++) { if (passed === true) break; passed = !!fn.call(context, this[k], k, this); } } return passed; };
5.every
every
表示是否“每一项”都要靠谱。
IE6-IE8扩展(与some
相比就是true
和false
调换一下):
6-IE8扩展(与some相比就是true和false调换一下): if (typeof Array.prototype.every != "function") { Array.prototype.every = function (fn, context) { var passed = true; if (typeof fn === "function") { for (var k = 0, length = this.length; k < length; k++) { if (passed === false) break; passed = !!fn.call(context, this[k], k, this); } } return passed; }; }
6.indexOf
array.indexOf(searchElement[, fromIndex])返回整数索引值,如果没有匹配(严格匹配),返回-1
.fromIndex
可选,表示从这个位置开始搜索,若缺省或格式不合要求,使用默认值0
if (typeof Array.prototype.indexOf != "function") { Array.prototype.indexOf = function (searchElement, fromIndex) { var index = -1; fromIndex = fromIndex * 1 || 0; for (var k = 0, length = this.length; k < length; k++) { if (k >= fromIndex && this[k] === searchElement) { index = k; break; } } return index; }; }
7.lastIndexOf
lastIndexOf
方法与indexOf
方法类似:
array.lastIndexOf(searchElement[, fromIndex])
只是lastIndexOf
是从字符串的末尾开始查找,而不是从开头。还有一个不同就是fromIndex
的默认值是array.length - 1
而不是0
.
IE6等浏览器如下折腾:
if (typeof Array.prototype.lastIndexOf != "function") { Array.prototype.lastIndexOf = function (searchElement, fromIndex) { var index = -1, length = this.length; fromIndex = fromIndex * 1 || length - 1; for (var k = length - 1; k > -1; k-=1) { if (k <= fromIndex && this[k] === searchElement) { index = k; break; } } return index; }; }
8.reduce
reduce
是JavaScript 1.8中才引入的,中文意思为“减少”、“约简”。不过,从功能来看,我个人是无法与“减少”这种含义联系起来的,反而更接近于“迭代”、“递归(recursion)”,擦,因为单词这么接近,不会是ECMA-262 5th制定者笔误写错了吧~~
array.reduce(callback(previous, current, index, array)[, initialValue])
callback
函数接受4个参数:之前值、当前值、索引值以及数组本身。initialValue
参数可选,表示初始值。若指定,则当作最初使用的previous
值;如果缺省,则使用数组的第一个元素作为previous
初始值,同时current
往后排一位,相比有initialValue
值少一次迭代。
var sum = [1, 2, 3, 4].reduce(function (previous, current, index, array) { return previous + current; }); console.log(sum); // 10
有了reduce
,我们可以轻松实现二维数组的扁平化:
var matrix = [ [1, 2], [3, 4], [5, 6] ]; // 二维数组扁平化 var flatten = matrix.reduce(function (previous, current) { return previous.concat(current); }); console.log(flatten); // [1, 2, 3, 4, 5, 6]
兼容处理IE6-IE8:
if (typeof Array.prototype.reduce != "function") { Array.prototype.reduce = function (callback, initialValue ) { var previous = initialValue, k = 0, length = this.length; if (typeof initialValue === "undefined") { previous = this[0]; k = 1; } if (typeof callback === "function") { for (k; k < length; k++) { this.hasOwnProperty(k) && (previous = callback(previous, this[k], k, this)); } } return previous; }; }
9.reduceRight
实现上差异在于reduceRight
是从数组的末尾开始实现。
var data = [1, 2, 3, 4]; var specialDiff = data.reduceRight(function (previous, current, index) { if (index == 0) { return previous + current; } return previous - current; }); console.log(specialDiff); // 0
为使低版本浏览器支持此方法,您可以添加如下代码:
if (typeof Array.prototype.reduceRight != "function") { Array.prototype.reduceRight = function (callback, initialValue ) { var length = this.length, k = length - 1, previous = initialValue; if (typeof initialValue === "undefined") { previous = this[length - 1]; k--; } if (typeof callback === "function") { for (k; k > -1; k-=1) { this.hasOwnProperty(k) && (previous = callback(previous, this[k], k, this)); } } return previous; }; }