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

本文介绍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' ]

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

(0)

相关推荐

  • 在NodeJS中启用ECMAScript 6小结(windos以及Linux)

    在NodeJS中启用ES6 (harmony) 版本: 开始吧, Linux下启用 来源: http://h3manth.com/new/blog/2013/es6-on-nodejs/ Node version : v0.11.6 先来看一看版本 harm ;) : $ node --v8-options | grep harm --harmony_typeof (enable harmony semantics for typeof) --harmony_scoping (enable ha

  • ECMAScript6的新特性箭头函数(Arrow Function)详细介绍

    箭头函数是ECMAScript 6最受关注的更新内容之一.它引入了一种用「箭头」(=>)来定义函数的新语法,它-它碉堡了~.箭头函数与传统的JavaScript函数主要区别在于以下几点:1.对 this 的关联.函数内置 this 的值,取决于箭头函数在哪儿定义,而非箭头函数执行的上下文环境.2.new 不可用.箭头函数不能使用 new 关键字来实例化对象,不然会报错.3.this 不可变.函数内置 this 不可变,在函数体内整个执行环境中为常量.4.没有arguments对象.更不能通过ar

  • 正则表达式字面量在ECMAScript5中的变化

    在<JavaScript语言精粹>的第72页有这样一段: 用正则表达式字面量创建的RegExp对象来共享同一个单实例: 复制代码 代码如下: function make_a_matcher( ) { return /a/gi; } var x = make_a_matcher( ); var y = make_a_matcher( ); // 注意:x 和 y 是同一个对象! x.lastIndex = 10; document.writeln(y.lastIndex); // 10当你在浏览

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

    本文介绍ECMAScript 6即将带给我们新的数组操作方法,以及在怎样在现有浏览器应用这些新的数组特性. Note: 我将使用交替使用构造器(constructor)和类(class)两个术语. 类方法 数组(Array)自身所拥有的方法. Array.from(arrayLike, mapFunc?, thisArg?) Array.from()的基本功能是,转换两种类型的对象成数组. 类数组对象(Array-like objects) 该类对象有长度与索引的属性.DOM操作符的结果即属于该

  • 解析array splice的移除数组中指定键的值,返回一个新的数组

    使用环境:人才网项目中有一个简历保密设置,其中有一个过滤关键词,只有某个企业的公司名中包含有其中的一个关键字,就不显示该份简历,当然,我还没有做到那里去,现在是要做关键词的增加删除.设想:不管一个人有多少份简历,所有简历都设置成一模一样的关键词过滤(主要是用的人也很少,所以这样存储无所谓,而且在搜索使用中很方便),然后将所有关键词组成一个用半角逗号分隔的字符串.难题:显示的时候我将字符串转化成数组然后再循环出来显示,但是我现在就是要删除指定的关键词.解决方案:既然转化成了数组,那么有值就有键,我

  • php小技巧 把数组的键和值交换形成了新的数组,查找值取得键

    复制代码 代码如下: $cityname = array_flip($city_DB[name]); //把数组的键和值交换形成了新的数组 $city_name = array_search($city_id,$cityname,true); //查找值取得键

  • PHP让数组中有相同值的组成新的数组实例

    实例如下所示: $arr = array( 0=>array('key1'=>'value1' , 'key2'=>'value2'), 1=>array('key1'=>'value1' , 'key2'=>'value3'), 2=>array('key1'=>'value2' , 'key2'=>'value4'), 999=>array('key1'=>'value2' , 'key2'=>'value5') ); $resu

  • 从Vuex中取出数组赋值给新的数组,新数组push时报错的解决方法

    如下所示: Uncaught Error: [vuex] Do not mutate vuex store state outside mutation handlers 今天遇到一个问题,将Vuex中数组的值赋给新的数组,新数组push时报上面的错误,代码如下 <code class="language-javascript">this.maPartListTable = this.$store.state.vehicleMa.maPartListTable; </

  • linux 不改变目录结构移动 home 目录到新分区的操作方法

    问题提出 公司的开发测试服务器部署在阿里云, 阿里云给出的实例一般都是只有一个分区, 20G到40G的样子, 然后再买存储挂载到其他目录. 而 home 目录是在这个 20G 的跟目录分区下的. 随着开发人员增多, 根目录分区很快被大家填满了. 因为是多地研发, 因此需要一个无感知的给大家的 home 搬家的方案. 基本原理 接到这个任务, 首先想到的就是 bind mount 方式: mount --bind /some/where /else/where 可以实现无感知搬家 home. 感觉

  • 带你入门Java的数组

    目录 数组的定义 数组的声明和创建 1.动态初始化 2.静态初始化 3.数组的默认初始化 数组的四个基本特点 数组边界 数组的使用 Arrays类 总结 数组的定义 数组是相同类型数据的有序集合 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们. 数组的声明和创建 首先必须声明数组变量,才能在程序中使用数组.下面是声明数组变量的语法: dataType[] arrayRefVar;//首选方法 或 data

  • 一篇文章带你入门C语言:数组

    目录 数组 一维数组 初始化 使用 总结: 内存存储 二维数组 创建 初始化 数组越界问题 数组作函数参数 应用实例 总结 数组 一维数组 创建 定义 数组是一组相同类型的元素的集合.那数组的语法形式: type_t arr_name [const_n] //如: int arr[10]; type_t 指的是数组元素的类型. const_n 指的是一个常量表达式,用来指定数组的大小. 此时运行程序的话,系统会报一个警告:未初始化变量.打开调试就会发现系统默认填入一些无意义的数据. 当然全局数组

  • 带你了解C++的数组与函数

    目录 数组作为函数的参数 数组参数的传递机制 数组作为函数的参数 传递首地址. A进行修改,a同时也会进行修改. 数组参数的传递机制

  • 带你粗略了解Java数组的使用

    目录 数组的定义 注意: 数组的创建及初始化: 1.数组的创建: 2.数组的初始化 ①动态初始化: ②静态初始化: 注意事项: 数组的使用 1.数组的长度: 2.数组的访问: 3.数组的遍历: 4.使用数组交换两个整数 5.以字符串的形式输出数组: 理解引用类型: 1.基本类型变量与引用类型变量的区别 2.认识null 3.数组作为方法的返回值 二维数组: 1.创建二维数组及初始化: 2.二维数组长度: 3.二维数组的打印: 4.不规则的二维数组: Array类: 总结 数组的定义 数组:可以看

随机推荐