您现在的位置:首页 >> 前端 >> 内容

ECMAScript6(11)——数组的扩展

时间:2017/5/25 9:36:00 点击:

  核心提示:0、一句话总结ECMAScript6(11)数组的扩展。可以将一个有Iterator接口的数据类型(arraylike)转为真正的数组; 将变量作为数组成员,返回一个新数组; 把数组内某些位置元素,复...

0、一句话总结

ECMAScript6(11)——数组的扩展。可以将一个有Iterator接口的数据类型(arraylike)转为真正的数组; 将变量作为数组成员,返回一个新数组; 把数组内某些位置元素,复制在数组内的某些位置; 用某个值填充满整个数组; 遍历数组的key、value和key + value; 以函数为筛选条件,找到数组中第一个符合条件的元素; 告诉你数组中有没有某个元素;

1、Array扩展方法

以下方法只能通过Array这个全局对象来访问,而不能通过例如以下几个方法来调用

Array.prototype.from;    //undefined
[].from;    //undefined
var a = [1];
a.from;    //undefined
var a = new Array();
a.from;    //undefined
var a = [];
a.__proto__.from;    //undefined

正确方法是:

typeof Array.from;    //"function"

1.1、基于已有对象创建数组

Array.from(arrayLike[, mapFn[, thisArg]])

效果是从一个类似数组或可迭代对象创建一个数组的实例;

参数1:被用于转换为数组的对象;不能
参数2:可选,处理函数,将数组的每个元素通过本函数处理后再返回。如果没有return内容,数组该位置元素的值将是undefined(而不是跳过这个元素);
参数3:参数2函数里this指向的目标,默认是window对象;

arrayLike

简单来说(不涉及极端和特殊情况),几种常见类型会如下处理:

 

1. undefined和null会抛出TypeError; 2. number会返回一个空数组; 3. boolean类型返回空数组; 4. 字符串会以单个字符为单位分拆为数组,例如”ab”变为[“a”, “b”]; 5. 数组还是数组(是一个新的数组,但是浅复制,而不是深度复制,即按引用传递的元素保持不变); 6. 类似数组的对象,会被转为数组,比如Array.from({'0':"1",length:2})输出["1", undefined],注意,必须有length属性才成立。其他情况会返回空数组; 7. 函数返回空数组(无论函数有没有返回值); 8. NodeList转为数组,如代码:

 

var list = document.querySelectorAll(".a");
console.log(Object.prototype.toString.call(list));  //[object NodeList]
console.log(Object.prototype.toString.call(Array.from(list)));  //[object Array]

 

9. 其他有Iterator接口的类型。

 

在ES6中,有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构。

所谓类似数组的对象,本质特征只有一点,即必须有length属性。
因此,任何有length属性的对象,都可以通过Array.from方法转为数组,而此时扩展运算符就无法转换。
但转换后,填充的时候就需要看key了,key符合才会被填充到对应位置;如果该位置key为空,那么值就是undefined。

更多内容等写了Iterator相关的内容后再回来补吧(如果我能想起来……)

mapFn

 

可选 处理函数,有点类似数组的map,有两个参数,分别是item(数组当前元素)和index(从0开始),没有第三个参数; 返回值将作为当前索引的值填充到数组中; 没有return的话当前位置为undefined;

 

thisArg

 

可选 mapFn里,this指向的目标

 

如果你有一个可以转换为数组的数据结构,比如NodeList,又想使用数组的各种api,那么就可以通过这个方法将该数据结构先转为数组,就可以方便的调用数组的各种API了。

1.2、生成数组

Array.of(element0[, element1[, …[, elementN]]])

说明:

生成一个新数组,然后将参数依次添加到该数组中,返回该数组。

如代码:

Array.of(1);    //[1]
Array.of("a", "c", "b");    //["a", "c", "b"]
Array.of();    //[]

注意:

假如某个参数是一个按引用传递类型,那么将按引用传递给新数组(而不是创建一个全新的按引用传递对象)。如:

var a = {};
var b = Array.of(a)
b;  //[{}]
b[0] === a;   //true

与new Array的区别:

new Array();    //[]
new Array(1);    //[undefined]
new Array(2);    //[undefined, undefined]
new Array(1, 2);    //[1, 2]
new Array("1");    //["1"]

也就是说,new Array假如参数为1个,并且参数类型为number,比如该参数为n时,他的效果是生成一个length为n,然后每个位置值都为undefined的数组。

而Array.of()无论参数是什么,是几个,都会将参数依次添加到一个新数组中并返回该数组;

2、数组实例的扩展方法

与1中不同,这里的方法不能直接通过Array.copyWithin来访问,而是需要通过prototype来访问。例如:

Array.copyWithin;    //undefined
typeof Array.prototype.copyWithin;    //"function"

2.1、数组元素在数组内复制

arr.copyWithin(target)
arr.copyWithin(target, start)
arr.copyWithin(target, start, end)

简单来说,这个api是这么做事的:

为了方便理解,以[1, 2, 3, 4, 5].copyWithin(a, b, c)为例

准备复制调用这个方法的数组,即[1,2,3,4,5] 找到参数2,该参数决定了从数组哪个索引位置开始复制(包含该位置),默认值为0。比如b=2, c默认时,复制的数组内容就是[3,4,5] 找到参数3,该参数决定了从数组哪个索引位置结束复制(但不包含该索引位置)。默认值为数组的长度。上面数组中,c默认为5。假如b=1,c=2,那么复制数组内容就是[1] 参数2和参数3如果是负数,则从末尾开始数,例如-1则表示数组最后一个元素的索引,注意参数2包含,参数3不包含该位置 通过参数2和参数3,从数组中找到了要被复制的部分。然后现在要决定将数组复制在哪里。 查看参数1,确定将数组从哪个索引位置开始替换,默认值为0。替换对应位置的数组元素。 不会超出数组原有长度 返回被修改后的数组


流程解释:

a=1,b,c默认值。于是b=0,c=5,复制内容为[1,2,3,4,5],从下标1开始替换。于是数组变为[1,1,2,3,4]。注意,不会超出

[1, 2, 3, 4, 5].copyWithin(1);    //[1, 1, 2, 3, 4]

 

a=1,b=3,c默认。于是c=5,复制内容为]4,5]。从下标1开始替换,于是数组变为[1,4,5,4,5]

[1, 2, 3, 4, 5].copyWithin(1,3);    //[1, 4, 5, 4, 5]

 

a=1,b=2,c=-2。于是c=3,复制内容为[3]。从下标1开始替换,于是数组变为[1,3,3,4,5]

[1, 2, 3, 4, 5].copyWithin(1,2,-2);    //[1, 3, 3, 4, 5]

2.2、数组的填充

arr.fill(value)
arr.fill(value, start)
arr.fill(value, start, end)

效果是将数组用数值填充。

参数1表示用于填充的值;
参数2表示填充的起始索引(含);
参数3表示填充的末尾索引(不含);
如果数组原位置有值,会覆盖原位置的值。

new Array(3).fill(3);    //[3,3,3],填充
[1,2].fill(3);    //[3,3],会覆写
[0, 0, 0].fill(1, 1);    //[0,1,1],可以设置起始填充位置
[0, 0, 0].fill(1, 0, 1);    //[1,0,0],也可以设置终止填充位置

如果按引用传递类型的话,填充的时候是同一个值。

var a = {};
var arr = new Array(3).fill(a);
arr;    //[{}, {}, {}]
arr[0] === arr[1];    //true

2.3、数组的遍历

arr.keys()
arr.values()
arr.entries()

用于遍历数组,分别可以取index,value和index + value。

注意:chrome、IE、火狐(至少53.0版本)不支持arr.values(),而edge支持

用法是通过for…of方法来使用,比较类似for…in方法。

如示例代码:

var arr = ["a", "b", "c"];
for (let key of arr.keys()) {
    console.log(key);
}
//0
//1
//2
//注意兼容性问题
var arr = ["a", "b", "c"];
for (let val of arr.values()) {
    console.log(val);
}
//"a"
//"b"
//"c"
var arr = ["a", "b", "c"];

//let kv又可以写成let [key, val]这种形式
for (let kv of arr.entries()) {
    console.log(kv);
}
//[0, "a"]
//[1, "b"]
//[2, "c"]

另外,以上方法返回的是一个Iterator(遍历器/迭代器)对象,可以通过该对象来遍历整个数组。具体来说请看以下示例代码:

var arr = ["a", "b", "c"];
var obj = arr.entries();    //obj通过next方法来遍历,此时obj指向该数组的起始位置(数组的第一个元素之前)
var first = obj.next();
//first:{done:false, value:[0,"a]}
//此时first是obj遍历到第一个对象后的结果,obj对象已经迭代到第一个元素

var second = obj.next();
//second:{done:false, value:[1,"b"]}
var third = obj.next();
//third:{done:false, value:[2,"c"]}

var end = obj.next();
//end:{done:true, value:undefined}
//此时遍历结束,因此done为true,并且value为undefined

另外,这个遍历器对象,只有next方法,而next方法会更新他自身状态。

也只有通过next方法返回的值(而非遍历器对象),才能获知当前是否遍历结束,以及遍历到当前目标的值是什么。

2.4、找到元素和元素的索引

arr.find(callback[, thisArg])

通过回调函数,查找到符合条件的第一个元素,并返回。

参数1是一个函数,这个函数会遍历整个数组。它有三个参数,分别是:当前元素,当前元素的索引,整个数组。有些类似arr.forEach,当返回值为true的时候,筛选成功,终止其后继续执行的代码。

参数2是回调函数中this指向的对象,参考其他此类api理解即可。

示例代码。

var a = {
    num: 1
}
var b = {
    num: 2
}
var c = {
    num: 3
}
var arr = [a, b, c];
var result = arr.find(function (item, index, array) {
    console.log(item.num, index);   //会依次输出1 0和2 1
    if (item.num > 1) {
        return true;
    } else {
        return false;
    }
})
console.log(result);    //{num: 2}
console.log(b === result);  //true,说明不是创建一个全新的元素并返回

arr.findIndex(callback[, thisArg])

和arr.find几乎一样,唯一区别是返回的是索引,而非数组元素。

将上面代码修改为如下后,返回值为1

.....
var result = arr.find(function (item, index, array) {
    ...
})
console.log(result);    //1

类似:

...
[a, b, c].indexOf(b);    //1

但相对来说,find和findIndex,扩展性更强(因为可以用回调函数),并且支持对NaN的查找(因为逻辑可以自己写)。

2.5、查看数组是否包含

arr.includes(searchElement)
arr.includes(searchElement, fromIndex)

2.4的方法,是通过作为参数的函数的返回值,来返回你需要的元素、或元素的索引,比较类似arr.indexOf()。

而这个更加类似indexOf(),这个方法直接传你要查找的元素,他只告诉你有、或没有。

indexOf()当有的时候返回非负整数,没有的时候返回-1。

使用这个方法需要注意以下几点:

可以判断NaN是否包含(indexOf()不行); 永远记住按引用传递类型,查看的是引用的对象是否一致。例如:[{}].includes({}); //false; 虽然兼容性对于现代浏览器还可以,但小心某些低版本的现代浏览器不支持;

2.6、数组的空位

具体去查看阮一峰的博客吧。

总而言之,良好的代码习惯是不要写类似

var arr = [,,];
//或
var arr = new Array(10);

这样的声明代码。而是写

var arr = [undefined, undefined, undefined];
//或
var arr = new Array(10);
arr.fill(undefined);

可以避免很多莫名其妙出现的bug。

Tags:EC CM MA AS 
作者:网络 来源:qq20004604