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 相关文章推荐
js限制文本框为整数和货币的函数代码
Oct 13 Javascript
jquery 取子节点及当前节点属性值的方法
Aug 24 Javascript
js+css实现tab菜单切换效果的方法
Jan 20 Javascript
如何实现chrome浏览器关闭页面时弹出“确定要离开此面吗?”
Mar 05 Javascript
JavaScript实现定时隐藏与显示图片的方法
Aug 06 Javascript
AngularJs中Bootstrap3 datetimepicker使用实例
Dec 13 Javascript
jq checkbox 的全选并ajax传参的实例
Apr 01 Javascript
JavaScript反弹动画效果的实现代码
Jul 13 Javascript
微信小程序实现红包功能(后端PHP实现逻辑)
Jul 11 Javascript
浅谈webpack+react多页面开发终极架构
Nov 11 Javascript
JS在Array数组中按指定位置删除或添加元素对象方法示例
Nov 19 Javascript
vue2.0实现列表数据增加和删除
Jun 17 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入门速成教程
2007/03/19 PHP
php include,include_once,require,require_once
2008/09/05 PHP
PHP单例模式详解及实例代码
2016/12/21 PHP
js活用事件触发对象动作
2008/08/10 Javascript
js history对象简单实现返回和前进
2013/10/30 Javascript
JQuery对表格进行操作的常用技巧总结
2014/04/23 Javascript
js实现局部页面打印预览原理及示例代码
2014/07/03 Javascript
js图片轮播手动切换效果
2015/11/10 Javascript
JavaScript实现自动生成网页元素功能(按钮、文本等)
2015/11/21 Javascript
Bootstrap select实现下拉框多选效果
2016/12/23 Javascript
Vue.js手风琴菜单组件开发实例
2017/05/16 Javascript
基于openlayers4实现点的扩散效果
2020/08/17 Javascript
JS/jQuery实现DIV延时几秒后消失或显示的方法
2018/02/12 jQuery
利用Blob进行文件上传的完整步骤
2018/08/02 Javascript
angular4+百分比进度显示插件用法示例
2019/05/05 Javascript
使用Python的Django框架结合jQuery实现AJAX购物车页面
2016/04/11 Python
用python制作游戏外挂
2018/01/04 Python
python+pyqt5编写md5生成器
2019/03/18 Python
24式加速你的Python(小结)
2019/06/13 Python
对python 中re.sub,replace(),strip()的区别详解
2019/07/22 Python
关于pandas的离散化,面元划分详解
2019/11/22 Python
django-csrf使用和禁用方式
2020/03/13 Python
使用Keras加载含有自定义层或函数的模型操作
2020/06/10 Python
Python中免验证跳转到内容页的实例代码
2020/10/23 Python
python爬取天气数据的实例详解
2020/11/20 Python
pandas针对excel处理的实现
2021/01/15 Python
HTML如何让IMG自动适应DIV容器大小的实现方法
2020/02/25 HTML / CSS
html5关于外链嵌入页面通信问题(postMessage解决跨域通信)
2020/07/20 HTML / CSS
linux面试题参考答案(10)
2016/10/26 面试题
毕业生就业自荐信
2013/12/04 职场文书
留学自荐信写作方法
2014/01/27 职场文书
小学生国庆65周年演讲稿范文(2篇)
2014/09/21 职场文书
解决go在函数退出后子协程的退出问题
2021/04/30 Golang
详解JS ES6编码规范
2021/05/07 Javascript
教你用python实现12306余票查询
2021/06/30 Python
Alexa停服!网站排名将何去何从?目前还没有替代品。
2022/04/15 杂记