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 相关文章推荐
LBS blog sql注射漏洞[All version]-官方已有补丁
Aug 26 Javascript
asp.net和asp下ACCESS的参数化查询
Jun 11 Javascript
Javascript this关键字使用分析
Oct 21 Javascript
google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)
Apr 24 Javascript
二叉树先序遍历的非递归算法具体实现
Jan 09 Javascript
js实现文本框中焦点在最后位置
Mar 04 Javascript
基于Vue如何封装分页组件
Dec 16 Javascript
基于JS设计12306登录页面
Dec 28 Javascript
微信小程序 常用工具类详解及实例
Feb 15 Javascript
js学习总结之DOM2兼容处理重复问题的解决方法
Jul 27 Javascript
vue实现下载文件流完整前后端代码
Nov 17 Vue.js
简单聊聊TypeScript只读修饰符
Apr 06 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闭包函数传参及使用外部变量的方法
2016/03/15 PHP
PHP数组函数array_multisort()用法实例分析
2016/04/02 PHP
PHP编译configure时常见错误的总结
2017/08/17 PHP
浅谈JavaScript中面向对象技术的模拟
2006/09/25 Javascript
在一个form用一个SUBMIT(或button)分别提交到两个处理表单页面的代码
2007/02/15 Javascript
js判断选择时间不能小于当前时间的示例代码
2013/09/24 Javascript
js+html5实现canvas绘制镂空字体文本的方法
2015/06/05 Javascript
JS实现的自定义右键菜单实例二则
2015/09/01 Javascript
JS在onclientclick里如何控制onclick的执行
2016/05/30 Javascript
Jquery给当前页或者跳转后页面的导航栏添加选中后样式的实例
2016/12/08 Javascript
基于JSON数据格式详解
2017/08/31 Javascript
bootstrap时间控件daterangepicker使用方法及各种小bug修复
2017/10/25 Javascript
详解Vue-cli中的静态资源管理(src/assets和static/的区别)
2018/06/19 Javascript
Angularjs实现页面模板清除的方法
2018/07/20 Javascript
深入理解JavaScript的值传递和引用传递
2018/10/24 Javascript
vue 搭建后台系统模块化开发详解
2019/05/01 Javascript
JS highcharts实现动态曲线代码示例
2020/10/16 Javascript
[57:22]完美世界DOTA2联赛PWL S2 FTD vs PXG 第二场 11.27
2020/12/01 DOTA
python实现的登陆Discuz!论坛通用代码分享
2014/07/11 Python
17个Python小技巧分享
2015/01/23 Python
Python迭代器和生成器介绍
2015/03/06 Python
教你用Type Hint提高Python程序开发效率
2016/08/08 Python
python编程线性回归代码示例
2017/12/07 Python
利用python和百度地图API实现数据地图标注的方法
2019/05/13 Python
python GUI图形化编程wxpython的使用
2019/07/19 Python
python 实现多维数组转向量
2019/11/30 Python
python爬虫模拟浏览器的两种方法实例分析
2019/12/09 Python
html5画布旋转效果示例
2014/01/27 HTML / CSS
Links of London官方网站:英国标志性的珠宝品牌
2017/04/09 全球购物
英国山地公路自行车商店:Tweeks Cycles
2018/03/16 全球购物
美国领先的在线邮轮旅游公司:CruiseDirect
2018/06/07 全球购物
如何清空Session
2015/02/23 面试题
小学教师学期末自我评价
2013/09/25 职场文书
总经理助理职责
2014/02/04 职场文书
公安机关起诉意见书
2015/05/20 职场文书
Html5同时支持多端sdk的小技巧
2021/11/17 HTML / CSS