S5中新增的Array方法详细说明
ES5中新增的Array方法详细说明
一、前言-索引
ES5中新增的不少东西,了解之对我们写JavaScript会有不少帮助,比如数组这块,我们可能就不需要去有板有眼地for
循环了。
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+
对于让人失望很多次的IE6-IE8浏览器,Array原型扩展可以实现以上全部功能,例如forEach
方法:
- // 对于古董浏览器,如IE6-IE8
- if (typeof Array.prototype.forEach != "function") {
- Array.prototype.forEach = function () {
- /* 实现 */
- };
- }
二、一个一个来
- forEach
forEach
是Array新方法中最基本的一个,就是遍历,循环。例如下面这个例子:- [1, 2 ,3, 4].forEach(alert);
等同于下面这个传统的
for
循环:- var array = [1, 2, 3, 4];
- for (var k = 0, length = array.length; k < length; k++) {
- alert(array[k]);
- }
Array在ES5新增的方法中,参数都是
function
类型,默认有传参,这些参数分别是?见下面:- [1, 2 ,3, 4].forEach(console.log);
- // 结果:
- // 1, 0, [1, 2, 3, 4]
- // 2, 1, [1, 2, 3, 4]
- // 3, 2, [1, 2, 3, 4]
- // 4, 3, [1, 2, 3, 4]
显而易见,
forEach
方法中的function
回调支持3个参数,第1个是遍历的数组内容;第2个是对应的数组索引,第3个是数组本身。因此,我们有:
- [].forEach(function(value, index, array) {
- // ...
- });
对比jQuery中的
$.each
方法:- $.each([], function(index, value, array) {
- // ...
- });
会发现,第1个和第2个参数正好是相反的,大家要注意了,不要记错了。后面类似的方法,例如
$.map
也是如此。现在,我们就可以使用
forEach
卖弄一个稍显完整的例子了,数组求和:- var sum = 0;
- [1, 2, 3, 4].forEach(function (item, index, array) {
- console.log(array[index] == item); // true
- sum += item;
- });
- alert(sum); // 10
再下面,更进一步,
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
- );
- // 结果:
- // 你好,张含韵
- // 抱歉,江一燕,你不是本家人
- // 抱歉,李小璐,你不是本家
如果这第2个可选参数不指定,则使用全局对象代替(在浏览器是为
window
),严格模式下甚至是undefined
.另外,forEach不会遍历纯粹“占着官位吃空饷”的元素的,例如下面这个例子:
- var array = [1, 2, 3];
- delete array[1]; // 移除 2
- alert(array); // "1,,3"
- alert(array.length); // but the length is still 3
- array.forEach(alert); // 弹出的仅仅是1和3
综上全部规则,我们就可以对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);
- }
- }
- };
- }
现在拿上面“张含韵”的例子测下我们扩展的
forEach
方法,您可能狠狠地点击这里:兼容处理的forEach方法demo例如IE7浏览器下:
- map 这里的
map
不是“地图”的意思,而是指“映射”。[].map();
基本用法跟forEach
方法类似:- array.map(callback,[ thisObject]);
callback
的参数也类似:- [].map(function(value, index, array) {
- // ...
- });
map
方法的作用不难理解,“映射”嘛,也就是原数组被“映射”成对应新数组。下面这个例子是数值项求平方:- var data = [1, 2, 3, 4];
- var arrayOfSquares = data.map(function (item) {
- return item * item;
- });
- alert(arrayOfSquares); // 1, 4, 9, 16
callback
需要有return
值,如果没有,就像下面这样:- var data = [1, 2, 3, 4];
- var arrayOfSquares = data.map(function() {});
- arrayOfSquares.forEach(console.log);
结果如下图,可以看到,数组所有项都被映射成了
undefined
:在实际使用的时候,我们可以利用
map
方法方便获得对象数组中的特定属性值们。例如下面这个例子(之后的兼容demo也是该例子):- var users = [
- {name: "张含韵", "email": "zhang@email.com"},
- {name: "江一燕", "email": "jiang@email.com"},
- {name: "李小璐", "email": "li@email.com"}
- ];
- var emails = users.map(function (user) { return user.email; });
- console.log(emails.join(", ")); // zhang@email.com, jiang@email.com, li@email.com
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;
- };
- }
您可以狠狠地点击这里:兼容map方法测试demo
结果显示如下图,IE6浏览器:
- filter
filter
为“过滤”、“筛选”之意。指数组filter
后,返回过滤后的新数组。用法跟map
极为相似:- array.filter(callback,[ thisObject]);
filter
的callback
函数需要返回布尔值true
或false
. 如果为true
则表示,恭喜你,通过啦!如果为
false
, 只能高歌“我只能无情地将你抛弃……”。
可能会疑问,一定要是
Boolean
值吗?我们可以简单测试下嘛,如下:- var data = [0, 1, 2, 3];
- var arrayFilter = data.filter(function(item) {
- return item;
- });
- console.log(arrayFilter); // [1, 2, 3]
有此可见,返回值只要是弱等于
== true/false
就可以了,而非非得返回=== true/false
.因此,我们在为低版本浏览器扩展时候,无需关心是否返回值是否是纯粹布尔值(见下黑色代码部分):
- 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;
- };
- }
接着上面
map
筛选邮件的例子,您可以狠狠地点击这里:兼容处理后filter方法测试demo主要测试代码为:
- var emailsZhang = users
- // 获得邮件
- .map(function (user) { return user.email; })
- // 筛选出zhang开头的邮件
- .filter(function(email) { return /^zhang/.test(email); });
- console.log(emailsZhang.join(", ")); // zhang@email.com
实际上,存在一些语法糖可以实现
map+filter
的效果,被称之为“数组简约式(Array comprehensions)”。目前,仅FireFox浏览器可以实现,展示下又不会怀孕:- var zhangEmails = [user.email for each (user in users) if (/^zhang/.test(user.email)) ];
- console.log(zhangEmails); // [zhang@email.com]
- some
some
意指“某些”,指是否“某些项”合乎条件。与下面的every
算是好基友,every
表示是否“每一项”都要靠谱。用法如下:- array.some(callback,[ thisObject]);
例如下面的简单使用:
- 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;
- };
- }
于是,我们就有了“朕准了”的demo,您可以狠狠地点击这里:兼容处理后的some方法demo
- every 跟
some
的基友关系已经是公开的秘密了,同样是返回Boolean值,不过,every
需要每一个妃子都要让朕满意,否则——“来人,给我拖出去砍了!”IE6-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;
- };
- }
还是那个朕的例子,您可以狠狠地点击这里:是否every妃子让朕满意demo
- if (scores.every(higherThanCurrent)) {
- console.log("朕准了!");
- } else {
- console.log("来人,拖出去斩了!");
- }
结果是:
- if (typeof Array.prototype.every != "function") {
- indexOf
indexOf
方法在字符串中自古就有,string.indexOf(searchString, position)
。数组这里的indexOf
方法与之类似。- array.indexOf(searchElement[, fromIndex])
返回整数索引值,如果没有匹配(严格匹配),返回
-1
.fromIndex
可选,表示从这个位置开始搜索,若缺省或格式不合要求,使用默认值0
,我在FireFox下测试,发现使用字符串数值也是可以的,例如"3"
和3
都可以。- var data = [2, 5, 7, 3, 5];
- console.log(data.indexOf(5, "x")); // 1 ("x"被忽略)
- console.log(data.indexOf(5, "3")); // 4 (从3号位开始搜索)
- console.log(data.indexOf(4)); // -1 (未找到)
- console.log(data.indexOf("5")); // -1 (未找到,因为5 !== "5")
兼容处理如下:
- 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;
- };
- }
一个路子下来的,显然,轮到demo了,您可以狠狠地点击这里:兼容处理后indexOf方法测试demo
下图为ietester IE6下的截图:
- 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;
- };
- }
于是,则有:
- var data = [2, 5, 7, 3, 5];
- console.log(data.lastIndexOf(5)); // 4
- console.log(data.lastIndexOf(5, 3)); // 1 (从后往前,索引值小于3的开始搜索)
- console.log(data.lastIndexOf(4)); // -1 (未找到)
懒得截图了,结果查看可狠狠地点击这里:lastIndexOf测试demo
- reduce
reduce
是JavaScript 1.8中才引入的,中文意思为“减少”、“约简”。不过,从功能来看,我个人是无法与“减少”这种含义联系起来的,反而更接近于“迭代”、“递归(recursion)”,擦,因为单词这么接近,不会是ECMA-262 5th制定者笔误写错了吧~~此方法相比上面的方法都复杂,用法如下:
- array.reduce(callback[, 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
说明:
- 因为
initialValue
不存在,因此一开始的previous
值等于数组的第一个元素。 - 从而
current
值在第一次调用的时候就是2
. - 最后两个参数为索引值
index
以及数组本身array
.
以下为循环执行过程:
- // 初始设置
- previous = initialValue = 1, current = 2
- // 第一次迭代
- previous = (1 + 2) = 3, current = 3
- // 第二次迭代
- previous = (3 + 3) = 6, current = 4
- // 第三次迭代
- previous = (6 + 4) = 10, current = undefined (退出)
有了
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;
- };
- }
然后,测试整合,demo演示,您可以狠狠地点击这里:兼容IE6的reduce方法测试demo
IE6浏览器下结果如下图:
- reduceRight
reduceRight
跟reduce
相比,用法类似:- array.reduceRight(callback[, initialValue])
实现上差异在于
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
结果
0
是如何得到的呢? 我们一步一步查看循环执行:- // 初始设置
- index = 3, previous = initialValue = 4, current = 3
- // 第一次迭代
- index = 2, previous = (4- 3) = 1, current = 2
- // 第二次迭代
- index = 1, previous = (1 - 2) = -1, current = 1
- // 第三次迭代
- index = 0, previous = (-1 + 1) = 0, current = undefined (退出)
为使低版本浏览器支持此方法,您可以添加如下代码:
- 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;
- };
- }
您可以狠狠地点击这里:reduceRight简单使用demo
对比FireFox浏览器和IE7浏览器下的结果:
三、更进一步的应用
我们还可以将上面这些数组方法应用在其他对象上。
例如,我们使用forEach遍历DOM元素。
- var eleDivs = document.getElementsByTagName("div");
- Array.prototype.forEach.call(eleDivs, function(div) {
- console.log("该div类名是:" + (div.className || "空"));
- });
可以输出页面所有div
的类名,您可以狠狠地点击这里:Array新方法forEach遍历DOM demo
结果如下,IE6下,demo结果:
等很多其他类数组应用。
四、最后一点点了
本文为低版本IE扩展的Array方法我都合并到一个JS中了,您可以轻轻的右键这里或下载或查看:es5-array.js
以上所有未IE扩展的方法都是自己根据理解写的,虽然多番测试,难免还会有细节遗漏的,欢迎指出来。
参考文章: JavaScript array “extras” in detail Array.forEach
原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com] 本文地址:http://www.zhangxinxu.com/wordpress/?p=3220
(本篇完)
S5中新增的Array方法详细说明的更多相关文章
- ES5中新增的Array方法详细说明
一.前言-索引 ES5中新增的不少东西,了解之对我们写JavaScript会有不少帮助,比如数组这块,我们可能就不需要去有板有眼地for循环了. ES5中新增了写数组方法,如下: forEach (j ...
- ECMAScript5中新增的Array方法实例详解
ECMAScript5标准发布于2009年12月3日,它带来了一些新的,改善现有的Array数组操作的方法.(注意兼容性) 在ES5中,一共有9个Array方法:http://kangax.githu ...
- 数组Array和字符串String的indexOf方法,以及ES7(ES2016)中新增的Array.prototype.includes方法
前言 我们在判断某一个字符是否存在于一个字符串中或者某一个值是否存在于一个数组中时,ES7之前我们需要使用indexOf,ES7引入了新的方法includes 语法 数组:Array.inexOf(s ...
- ECMAScript 5 新增的Array方法
引自:by zhangxinxu from http://www.zhangxinxu.com ES5中新增了写数组方法,如下: forEach (js v1.6) map (js v1.6) fil ...
- ECMAScript 5中新增的数组方法
ECMAScript 5中定义了9个新的数组方法,用于遍历.映射.过滤.检测.简化和搜索数组. 在开始介绍之前,很有必要对这几个新增的数组方法做一个概述.首先,大多数方法的第一个参数接收一个函数,并且 ...
- AS2在FLASH中调用EXE文件方法详细说明 已测试可行
熟悉FLASH功能的朋友都知道fscommand在FLASH中是一个经常用来控制窗口全屏或退出的命令,同时它也是FLASH调用外部可执行程序的一种方法,使用fscommand命令格式如下: fscom ...
- ES6中新增的字符串方法
实例方法:includes(), startsWith(), endsWith() 传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中.ES6 又提供 ...
- JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】
写在前面,欢迎大家关注小编的微信公众号!!谢谢大家!! 一.前言 String字符串在我们日常开发中最常用的,当然还有他的两个兄弟StringBuilder和StringBuilder.他三个的区别也 ...
- HTML5自学笔记[ 4 ]js中新增的选择器方法
querySelector():参数与jQuery一样,这个方法获取一组元素中的第一个元素. querySelectorAll():获取一组元素. getElementsByClassName():获 ...
随机推荐
- python学习 小游戏
基于python3.4 while循环 #!/usr/bin/python3 #-*- coding=utf-8 -*- import random import sys import os luck ...
- 矿场搭建(codevs 1996)
题目描述 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使 ...
- 模拟赛1030d1
[问题描述]从1− ?中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少.[输入格式]第一行一个数字?.[输出格式]一行一个整数代表答案对100000007取模之后的答案.[样例 ...
- linux rpm问题:怎样查看rpm安装包的安装路径
x rpm问题:怎样查看rpm安装包的安装路径 2010-07-12 21:19:15 标签:rpm linux 路径 休闲 职场 rpm -qpl xxxxxx.rpm 1.如何安装rpm软件包 ...
- JS获取阴历阳历和星期
获取当前阳历日期时间,阴历日期和星期,三者分开,可自行调整顺序. 新建JS文件getdates.js,代码如下:/*获取当前阳历日期*/function getCurrentDateTime() { ...
- Xcode - 修改变量名、类名及字符串的替换操作
在做iOS开发代码优化的工作时,优化代码结构之前,我们应该先整理好工程的外貌,将文件和类的命名进行规范,在Xcode中为我们提供了方便而强大的名称修改功能. 第一步:修改类名 将鼠标点击放在类的名称上 ...
- 3.2 STL中的函数对象类模板
*: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. ...
- Clr Via C#读书笔记----基元线程同步构造
线程文章:http://www.cnblogs.com/edisonchou/p/4848131.html 重点在于多个线程同时访问,保持线程的同步. 线程同步的问题: 1,线程同步比较繁琐,而且容易 ...
- 与你相遇好幸运,Linux常用命令
开机挂载硬盘 cat /etc/fstab /dev/sda1 /mnt/sda1 ext3 defaults 0 0 挂载硬盘 mount /dev/sdb5 /home/dis ...
- Delphi中exit、break、continue等跳出操作的区别
Delphi中表示跳出的有break,continue,abort,exit,halt,runerror等 1.break 强制退出最近的一层循环(注意:只能放在循环里:而且是只能跳出最近的一层循环) ...