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 相关文章推荐
JavaScript String.replace函数参数实例说明
Jun 06 Javascript
无缝滚动js代码通俗易懂(自写)
Jun 19 Javascript
JavaScript通过元素索引号删除数组中对应元素的方法
Mar 18 Javascript
JQuery遍历DOM节点的方法
Jun 11 Javascript
jquery之别踩白块游戏的简单实现
Jul 25 Javascript
Js动态设置rem来实现移动端字体的自适应代码
Oct 14 Javascript
EasyUI折叠表格层次显示detailview详解及实例
Dec 28 Javascript
Angular2整合其他插件的方法
Jan 20 Javascript
详解Next.js页面渲染的优化方案
Jan 27 Javascript
Vue 使用beforeEach实现登录状态检查功能
Oct 31 Javascript
基于原生js实现判断元素是否有指定class名
Jul 11 Javascript
一文了解JavaScript用Element Traversal新属性遍历子元素
Nov 27 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 echo 输出字符串函数详解
2010/05/13 PHP
解析PHP中的file_get_contents获取远程页面乱码的问题
2013/06/25 PHP
PHP内核探索:哈希表碰撞攻击原理
2015/07/31 PHP
laravel 实现设置时区的简单方法
2019/10/10 PHP
关于Aptana Studio生成自动备份文件的解决办法
2009/12/23 Javascript
jsvascript图像处理—(计算机视觉应用)图像金字塔
2013/01/15 Javascript
弹出窗口并且此窗口带有半透明的遮罩层效果
2014/03/13 Javascript
jQuery实现Email邮箱地址自动补全功能代码
2015/11/03 Javascript
Sublime Text 3常用插件及安装方法
2015/12/16 Javascript
JS设置cookie、读取cookie
2016/02/24 Javascript
js传值后台中文出现乱码的解决方法
2016/06/30 Javascript
Node.js的文件权限及读写flag详解
2016/10/11 Javascript
JS中绑定事件顺序(事件冒泡与事件捕获区别)
2017/01/24 Javascript
微信小程序中的onLoad详解及简单实例
2017/04/05 Javascript
详解Angular2响应式表单
2017/06/14 Javascript
微信小程序 获取二维码实例详解
2017/06/23 Javascript
利用node.js实现自动生成前端项目组件的方法详解
2017/07/12 Javascript
jqgrid实现简单的单行编辑功能
2017/09/30 Javascript
vue中遇到的坑之变化检测问题(数组相关)
2017/10/13 Javascript
JavaScript数据结构之单链表和循环链表
2017/11/28 Javascript
微信小程序icon组件使用详解
2018/01/31 Javascript
Vue-cli中为单独页面设置背景色的实现方法
2018/02/11 Javascript
Django Rest framework之权限的实现示例
2018/12/17 Python
python 利用文件锁单例执行脚本的方法
2019/02/19 Python
python代码编写计算器小程序
2020/03/30 Python
简单分析python的类变量、实例变量
2019/08/23 Python
利用Python实现斐波那契数列的方法实例
2020/07/26 Python
接口中的方法可以是abstract的吗
2015/07/23 面试题
中年人生感言
2014/02/04 职场文书
学生打架检讨书
2014/02/14 职场文书
2014年大学生党课心得体会范文
2014/03/29 职场文书
工商企业管理专业自荐信范文
2014/04/12 职场文书
2015新年寄语大全
2014/12/08 职场文书
歌咏比赛主持词
2015/06/29 职场文书
医院感染管理制度
2015/08/05 职场文书
python turtle绘制多边形和跳跃和改变速度特效
2022/03/16 Python