ECMAScript 6即将带给我们新的数组操作方法前瞻


Posted in Javascript onJanuary 06, 2015

本文介绍ECMAScript 6即将带给我们新的数组操作方法,以及在怎样在现有浏览器应用这些新的数组特性。

Note: 我将使用交替使用构造器(constructor)和类(class)两个术语。

类方法
数组(Array)自身所拥有的方法。

Array.from(arrayLike, mapFunc?, thisArg?)

Array.from()的基本功能是,转换两种类型的对象成数组。

类数组对象(Array-like objects)

该类对象有长度与索引的属性。DOM操作符的结果即属于该类,如document.getElementsByClassName()。

可迭代对象(Iterable objects)

这类对象在取值时,每次只能取一个元素。数组是可迭代的,就如ECMAScript中新的数组结构,映射(Map)和集(Set)。

以下代码是一个转换类数组对象到数组的一个示例:

let lis = document.querySelectorAll('ul.fancy li');

Array.from(lis).forEach(function (li) {

  console.log(node);

});

querySelectorAll()的结果不是一个数组,也不会有forEach()这个方法。这是我们需要在使用这个方法之前,将它转换成数组的原因。

通过Array.from()使用Mapping
Array.from()同样也是一个泛型使用map()的替代选择。

let spans = document.querySelectorAll('span.name');

// map(), generically:

let names1 = Array.prototype.map.call(spans, s => s.textContent);

// Array.from():

let names2 = Array.from(spans, s => s.textContent);

两个方法中的第二个参数,都是箭头函数(arrow function)。
在这个示例中,document.querySelectorAll()的结果又是一个类数组对象,而非数组。这就是我们不能直接调用map()的原因。第一个示例中,为了使用forEach(),我们将类数组对象转换成了数组。这里我们通过泛型方法和两个参数版本的Array.from(),而省去了中间步骤。

Holes
Array.from()会忽略数组里缺失的元素 - 洞(holes),它会以未定义的元素(undefined elements)进行对待。

> Array.from([0,,2])

[ 0, undefined, 2 ]

这就意味着,你可以使用Array.from()来创建或者填充一个数组:

> Array.from(new Array(5), () => 'a')

[ 'a', 'a', 'a', 'a', 'a' ]

> Array.from(new Array(5), (x,i) => i)

[ 0, 1, 2, 3, 4 ]

如果你想用一个固定的值去填充一个数组,那么Array.prototype.fill()(请看下文)将是一个更好的选择。第一个即是以上示例的两种方式。

在数组(Array)子类中的from()
另一个Array.from()的使用场景是,转换类数组对象或可迭代对象到一个数组(Array)子类的一个实例。如你创建了一个Array的子类MyArray,想将此类对象转化成MyArray的一个实例,你就可以简单地使用MyArray.from()。可以这样使用的原因是,在ECMAScript 6中构造器(constructors)会继承下去(父类构造器是它子类构造器的原型(prototype))。

class MyArray extends Array {

  ...

}

let instanceOfMyArray = MyArray.from(anIterable);

你可以将该功能与映射(mapping)结合起来,在一个你控制结果构造器的地方完成映射操作(map operation):

// from() ? determine the result's constructor via the receiver

// (in this case, MyArray)

let instanceOfMyArray = MyArray.from([1, 2, 3], x => x * x);

// map(): the result is always an instance of Array

let instanceOfArray   = [1, 2, 3].map(x => x * x);

Array.of(...items)

如果你想将一组值转换成一个数组,你应该使用数组源文本(array literal)。特别是只有一个值且还是数字的时候,数组的构造器便罢工了。更多信息请参考。

> new Array(3, 11, 8)

[ 3, 11, 8 ]

> new Array(3)

[ , ,  ,]

> new Array(3.1)

RangeError: Invalid array length

便如果要将一组值转换成数字子构造器(sub-constructor)的一个实例,我们应该怎么做呢?这就是Array.of()存在的价值(记住,数组子构造器会继承所有的数组方法,当然也包括of())。

class MyArray extends Array {

  ...

}

console.log(MyArray.of(3, 11, 8) instanceof MyArray); // true

console.log(MyArray.of(3).length === 1); // true

把值包裹嵌套在数组里,Array.of()会相当方便,而不会有Array()一样怪异的处理方式。但也要注意Array.prototype.map(),此处有坑:

> ['a', 'b'].map(Array.of)

[ [ 'a', 0, [ 'a', 'b' ] ],

[ 'b', 1, [ 'a', 'b' ] ] ]

> ['a', 'b'].map(x => Array.of(x)) // better

[ [ 'a' ], [ 'b' ] ]

> ['a', 'b'].map(x => [x]) // best (in this case)

[ [ 'a' ], [ 'b' ] ]

如你所看,map()会传递三个参数到它的回调里面。最后两个又是经常被忽略的(详细)。

原型方法(Prototype methods)
数组的实例会有很多新的方法可用。

数组里的迭代(Iterating over arrays)

以下的方法,会帮助完成在数组里的迭代:

Array.prototype.entries()

Array.prototype.keys()

Array.prototype.values()

以上的每一个方法都会返回一串值,却不会作为一个数组返回。它们会通过迭代器,一个接一个的显示。让我们看一个示例(我将使用Array.from()将迭代器的内容放在数组中):

> Array.from([ 'a', 'b' ].keys())

[ 0, 1 ]

> Array.from([ 'a', 'b' ].values())

[ 'a', 'b' ]

> Array.from([ 'a', 'b' ].entries())

[ [ 0, 'a' ],

[ 1, 'b' ] ]

你可以结合entries()和ECMAScript 6中的for-of循环,方便地将迭代对象拆解成key-value对:

for (let [index, elem] of ['a', 'b'].entries()) {

  console.log(index, elem);

}

Note: 这段代码已经可以在最新的Firefox浏览器里运行了。t Firefox.

查找数组元素

Array.prototype.find(predicate, thisArg?) 会返回满足回调函数的第一个元素。如果没有任何一个元素满足条件,它会返回undefined。比如:

> [6, -5, 8].find(x => x < 0)

-5

> [6, 5, 8].find(x => x < 0)

undefined

Array.prototype.findIndex(predicate, thisArg?)

会返回满足回调函数的第一个元素的索引。如果找不任何满足的元素,则返回-1。比如:

> [6, -5, 8].findIndex(x => x < 0)

1

> [6, 5, 8].findIndex(x => x < 0)

-1

两个find*方法都会忽略洞(holes),即不会关注undefined的元素。回调的完成函数签名是:

predicate(element, index, array)
通过findIndex()找NaN

Array.prototype.indexOf()有一个大家所熟知的限制,那就是不能查找NaN。因为它用恒等(===)查找匹配元素:

> [NaN].indexOf(NaN)

-1

使用findIndex(),你就可以使用Object.is(),这就不会产生这样的问题:

> [NaN].findIndex(y => Object.is(NaN, y))

0

你同样也可以采用更通用的方式,创建一个帮助函数elemIs():

> function elemIs(x) { return Object.is.bind(Object, x) }

> [NaN].findIndex(elemIs(NaN))

0

Array.prototype.fill(value, start?, end?)

用所给的数值,填充一个数组:

> ['a', 'b', 'c'].fill(7)

[ 7, 7, 7 ]

洞(Holes)也不会有任何的特殊对待:

> new Array(3).fill(7)

[ 7, 7, 7 ]

你也可以限制你填充的起始与结束:

> ['a', 'b', 'c'].fill(7, 1, 2)

[ 'a', 7, 'c' ]

什么时候可以使用新的数组方法?
有一些方法已经可以在浏览器里使用了。

Javascript 相关文章推荐
点击按钮或链接不跳转只刷新页面的脚本整理
Oct 22 Javascript
jQuery实现带延迟效果的滑动菜单代码
Sep 02 Javascript
基于JavaScript操作DOM常用的API小结
Dec 01 Javascript
JavaScript中Number对象的toFixed() 方法详解
Sep 02 Javascript
微信小程序商城项目之淘宝分类入口(2)
Apr 17 Javascript
微信小程序--onShareAppMessage分享参数用处(页面分享)
Apr 18 Javascript
vue 权限认证token的实现方法
Jul 17 Javascript
浅谈vue同一页面中拥有两个表单时,的验证问题
Sep 18 Javascript
详解使用element-ui table组件的筛选功能的一个小坑
Nov 02 Javascript
微信小程序手动添加收货地址省市区联动
May 18 Javascript
一篇文章带你使用Typescript封装一个Vue组件(简单易懂)
Jun 05 Javascript
javascript前端和后台进行数据交互方法示例
Aug 07 Javascript
jQuery中hasClass()方法用法实例
Jan 06 #Javascript
jQuery中last()方法用法实例
Jan 06 #Javascript
jQuery中first()方法用法实例
Jan 06 #Javascript
jquery解决客户端跨域访问问题
Jan 06 #Javascript
angular.foreach 循环方法使用指南
Jan 06 #Javascript
angularjs 处理多个异步请求方法汇总
Jan 06 #Javascript
json实现前后台的相互传值详解
Jan 05 #Javascript
You might like
使用字符串函数输出整数化的PHP版本号
2006/10/09 PHP
function.inc.php超越php
2006/12/09 PHP
php读取文件内容的几种方法详解
2013/06/26 PHP
使用openssl实现rsa非对称加密算法示例
2014/01/24 PHP
PHP session 会话处理函数
2016/06/06 PHP
php使用curl_init()和curl_multi_init()多线程的速度比较详解
2018/08/15 PHP
tp5(thinkPHP5框架)时间查询操作实例分析
2019/05/29 PHP
php实现文件上传基本验证
2020/03/04 PHP
背景图跟随鼠标移动的Mootools插件实现代码
2011/12/12 Javascript
angular内置provider之$compileProvider详解
2017/09/27 Javascript
nodejs用gulp管理前端文件方法
2018/06/24 NodeJs
vue+axios 前端实现登录拦截的两种方式(路由拦截、http拦截)
2018/10/24 Javascript
jQuery实现上下滚动公告栏详细代码
2018/11/21 jQuery
jQuery中使用validate插件校验表单功能
2019/05/24 jQuery
如何给element添加一个抽屉组件的方法步骤
2019/07/14 Javascript
使用layui监听器监听select下拉框,事件绑定不成功的解决方法
2019/09/28 Javascript
VSCode搭建React Native环境
2020/05/07 Javascript
React Native登录之指纹登录篇的示例代码
2020/11/03 Javascript
Python设计模式编程中解释器模式的简单程序示例分享
2016/03/02 Python
Python性能提升之延迟初始化
2016/12/04 Python
Python调用系统底层API播放wav文件的方法
2017/08/11 Python
用tensorflow实现弹性网络回归算法
2018/01/09 Python
python中字符串数组逆序排列方法总结
2019/06/23 Python
python实现查找所有程序的安装信息
2020/02/18 Python
css3中transition属性详解
2014/09/02 HTML / CSS
Css3新特性应用之视觉效果实例
2016/12/12 HTML / CSS
CSS3 不定高宽垂直水平居中的几种方式
2020/03/26 HTML / CSS
韩国CJ食品专卖网:CJonmart
2016/09/11 全球购物
英国团购网站:Groupon英国
2017/11/28 全球购物
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
REN Clean Skincare官网:英国本土有机护肤品牌
2019/02/23 全球购物
天地会口号
2014/06/17 职场文书
迎国庆演讲稿
2014/09/05 职场文书
2014年最新领导班子整改方案
2014/09/27 职场文书
关于学习的决心书
2015/02/05 职场文书
python scrapy简单模拟登录的代码分析
2021/07/21 Python