ES6专栏 - ES6对于数组新增的常用新特性(Array.from, Array.of等)

ES6给数组增加的常用新特性

目录(红色为相对来说比较重要的):

  1. spread运算符

  2. Array.from

  3. Array.of

  4. 实例方法: copyWithin()

  5. 实例方法: findIndex() , find()

  6. 实例方法: fill()

  7. 实例方法: entries(), keys(), values()

  8. 实例方法: includes

spread运算符

在之前的专栏中我应该有跟大家提到过rest运算符..., 在解构赋值中我们常用他来收集剩余参数, 当时应该顺带提过一嘴, 这哥们还有个展开的作用, 而当他进行展开作用的使用时, 官方将它称之为扩展运算符(spread), 他的使用方法相对来说比较简单所以我直接用实例, 相信你看到实例会恍然大悟(如果你之前有看过我关于解构的专栏的话)

spread运算符应用场景实例

数组的非地址拷贝

在ES5中, 如果我们要将一个数组拷贝给另一个数组且不仅仅是复制地址的话, 我们通常会使用数组的原型方法巧取新数组

var arr = ['fst', 'sec', 'trd'];

var fstArr = arr; // 这样仅仅是在拷贝地址
console.log(fstArr === arr); // true

var secArr = arr.concat([]); 
console.log(secArr === arr); //false

var trdArr = arr.slice();
console.log(trdArr === arr); //false

// 还有很多的获取新数组的方法, 就不一一列举了

而在ES6中, 我们可以通过扩展运算符来获取一个新数组, 这样的写法会让人觉得更加的舒服, 代码的可读性也大很多

const arr = ['fst', 'sec', 'trd'];
const newArr = [...arr]; // 将arr数组展开放进一个新数组中
console.log(arr === newArr); //false

转化元素类数组

而这个扩展运算符的作用还不止于此, 我们可以通过扩展运算符将一个元素类数组(nodeList)转化为真正的数组

const divs = document.querySelectorAll('div');
console.log(divs.map); //由于是类数组, 所以有些数组上的方法我们并不能使用
const domArr = [...divs];
console.log(domArr.map); // 已经是真正的数组了所以可以在原型中找到map方法

而将元素类数组转化为数组, 在ES5中我们不得不这么做

var divs = document.querySelectorAll('div');
const domArr = [].slice.call(divs);

一般的类数组和对象我们是没办法进行展开的, 因为他们没有部署迭代接口, 至于迭代接口是什么我们在后面会有介绍, 如果你必须要将一个类数组转化为数组, 可以使用Array.from, 也是我们下一个要讲的内容

数组的合并

在ES5中, 我们如果要合并两个数组, 我们一般可能会这样做

var arr = [1, 2, 3];
var arr2 = [4, 5, 6];
var newArr = arr.concat(arr2);
console.log(newArr); // [1, 2, 3, 4, 5, 6]

在ES6中, 扩展运算符让一切变得特别的自然

const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
const newArr = [...arr, ...arr2];
console.log(newArr); // [1, 2, 3, 4, 5, 6]

与解构的不解之缘(收集作用)

解构赋值跟...运算符的巧妙使用在解构那一篇中我已经写得比较详细了, 这里再提一嘴

在ES5中, 如果我们需要将一个数组拆分开, 把数组的第一位给一个变量, 而数组的剩余所有数据都放进一个数组的话

var arr = ['loki', 'thor', 'monkey'];

var userName = arr[0];
var restArr = arr.slice(1);

console.log(userName, restArr); // loki  ["thor", "monkey"]

而在ES6中, 我们可以将rest运算符跟解构联合

const arr = ['loki', 'thor', 'monkey'];
const [ userName, ...restArr ] = arr;
console.log(userName, restArr); // loki  ["thor", "monkey"]

关于解构跟...运算符还有很多细节, 这里不多说了, 可以去看我专栏中专门描述解构赋值的一章

将字符串转化为数组

在ES5中, 官方给我们提供了split方法来实现字符串转换为数组

var str = 'loki';
var arr = str.split('');
console.log(arr); // ['l', 'o', 'k', 'i']

ES6追求的就是一种简洁自然, 干净清爽的状态

const str = 'loki';
const arr = [...str];
console.log(arr); // ['l', 'o', 'k', 'i']

任何部署了迭代接口的数据结构都可以通过扩展运算符将其转化为真正的数组

在这块的话, 可能你们还不是很了解迭代接口是什么概念, 实际上元素类数组(nodeList)就是部署有迭代接口的, 所以我们可以将它直接转化为新的数组, 迭代接口在后面我会详细介绍, 到时候也会提一嘴这里的事儿

而如果没有部署迭代接口的会直接报错

比如一个对象

let obj = {
    name: 'loki',
    age: 18
}

const arr = [...obj]; // 报错: TypeError: can't spread non-iterable object

Array.from(data, handle)

Array.from 致力于将两种数据结构转化为真正的数组,Array.from 的第一个参数就是你想要转化为真数组的数据结构

  1. 类数组

在ES5中将一个类数组转化为数组的方法我在上面已经写过了, [].slice.call, 同时spread运算符也只能展开带有迭代接口的数据结构

那么在ES6中, Array.from 也帮你自然的将一个类数组转化为数组

const likeArr = {
    '0': 'loki',
    '1': 'thor',
    'length': 2
}

const newArr = Array.from(likeArr);
console.log(newArr); // ["loki", "thor"]
  1. 可遍历对象, 包括ES6的Set和Map

ES6规定, 任何具有迭代接口的数据结构都可以被Array.from转化为真正的数组, 比如字符串

const str = 'hello';
const strArr = Array.from(str);

而至于ES6新的部署迭代接口的数据结构, 暂时你可以不必深究, 当你学习到那块的时候自然会明白什么是Set什么是Map

Array.from 的第二个参数

Array.from的第二个参数类似于数组的map方法, 它允许你对你所传入的数据结构中的每一项进行一定的处理以后再将处理后的值放入新的数组

const str = 'abc';
const strArr = Array.from(str, ele => ele + 1);
console.log(strArr); // ["a1", "b1", "c1"]

// 你可以把上面的写法理解为
// const strArr = Array.from(str).map(ele => ele + 1);

如果我们填入的第一个参数本身就是一个真实数组, 那么 Array.from会返回给我们一个一模一样但是地址不同的新数组

const arr = ['loki', 'thor'];
const newArr = Array.from(arr);
console.log(arr, newArr, arr === newArr);
// ["loki", "thor"], ["loki", "thor"], false

Array.of

Array.of这个方法主要是用来弥补ES6之前数组构造函数的缺陷

我们来看看ES5中我们使用构造函数的场景

var arr = new Array(); 
consle.log(arr); // []相对来说比较合理

var arr = new Array(1, 2, 3); // [1, 2, 3], 也比较合理

var arr = new Array(3); // [, , ,] 这就不太对了, 我其实是想数组就只有一位, 值为3

看了上面的例子, 你应该就知道为什么我们几乎都是用字面量建立数组了, 因为真的很卑微, 于是ES6推出了Array.of来弥补开发者

const arr = Array.of(); // []
const secArr = Array.of(1); // [1]
const trdArr = Array.of(1, 2, 3); // [1, 2, 3]

实际上 Array.of的原理也很简单的

Array.of = function() {
    return [].slice.call(arguments); 
}

copyWithin(target, start, end)

数组实例上的copyWithin方法就是把一个数组中的某一个索引位的值复制一遍, 然后赋值给另一个索引位,并改变该数组的原数组

这是我总结出来的话, 如果觉得看不懂没关系, 不看了, 直接看使用方法, 看完使用方法就懂了

这个方法接收三个参数

  • target: 从该位置开始替换数据必填

  • start: 默认值0, 从该位置开始读取数据, 如果为-1就是倒数

  • end: 默认length, 读取到该位置结束, 同理为-1就是倒数

直接上实例:

const arr = ['loki', 'thor', 'diana', 'ben']

arr.copyWithin(0, 2, 4);
// 就是我去找数组第二位到第四位的值,
//  然后将这两个值从第0位开始替换, 于是arr变成了如下
console.log(arr); //  ['diana', 'ben','diana', 'ben']

这个方法相对来说没那么使用的频繁, 我提出来也是让你在以后遇到这个需求的时候脑子有这么个印象说ES6有这么个方法可以进行数组的替换

find() 和findIndex()

在ES5中我们要进行对于数组中数组元素的查找一般会使用indexOf, 或者filter之类的, 如下

var arr = ['loki', 'thor'];
let result = arr.indexOf('loki');
console.log(result); // 返回索引 - 0

而在ES6中, Es6给我们提供了更加精准的寻找内容的方法, 说白话这两哥们就是ES6拿出来帮你找人的, 咱来看看他们是咋找的人

find(func)

find用于寻找到数组中第一个符合条件的成员并返回成员值, 他接收一个参数, 该参数为一个函数, 如果你用过字符串的filter, sort方法的话应该能够联想到, 参数函数会有一个返回值用来返回寻找的规则

const arr = ['loki', 'thor'];

const value = arr.find(ele => ele === 'loki');
console.log(value); // 返回loki


const numberArr = [1, 2, 3];
const number = numberArr.find(ele => ele > 1);
console.log(number); // 2 
// 记住这哥们是找到符合条件的第一个, filter是找到符合条件的所有

findIndex(func)

findIndex无论是参数还是使用方式都与find一致, 两人唯一的区别也就是find是将成员值返回, 而findIndex是返回成员索引

const arr = ['loki', 'thor'];

const value = arr.findIndex(ele => ele === 'loki');
console.log(value); // 返回索引值 - 0


const numberArr = [1, 2, 3];
const number = numberArr.findIndex(ele => ele > 1);
console.log(number); // 返回的是索引值 - 1
// 记住这哥们是找到符合条件的第一个, filter是找到符合条件的所有

同时这两哥们都可以找到NaN, 而在过去的indexOf中并不能办到

[NaN].indexOf(NaN); // -1
[NaN].find(NaN); // NaN
[NaN].findIndex(NaN); // 0

至于实现原理的话我想不用多说吧, 字符串转化

再提一嘴的就是, 这个两个方法都可以接收第二个参数用来绑定第一个回调函数的this指向, 但是这个用到的实在是少

fill()

数组实例上的fill方法用于填充数组元素, 用给定参数值给调用它的数组填充值

let arr = [];
arr.fill('thor');
console.log(arr); // ["thor"]

let secArr = new Array(3).fill('loki')
console.log(secArr); // ["loki", "loki", "loki"]

这个方法还可以接收第二个参数, 用于确认填充起始位置和结束位置, 比如我现在有个需求, 这里有一个数组我需要将其中的第三项改为’hellWorld’, 操作如下

let arr = ['loki', 'thor', 'monkey'];

arr.fill('helloWorld', 2, 3);
console.log(arr); //["loki", "thor", "helloWorld"]

这个方法也是了解一下就好, 至少以后遇到这种情况你知道ES6还有一个可以进行填充的方法

entries(), keys(), values()

es6提供了entries, keys, values这三个全新的方法给我们用来遍历数组, 这三个方法都会返回一个遍历器对象, 什么是遍历器对象以后我会介绍, 当下混个脸熟就好, 而这个遍历器对象可以用for…of进行循环取值

直接上实例吧, 看得懂的就看着, 看不懂的先混个脸熟

const arr = ['loki', 'thor'];
const entriesResult = arr.entries();
const keyResult = arr.keys();
const valueResult = arr.values();

console.log(entriesResult, keyResult, valueResult);

遍历器对象就是下面这样, 看不懂也没关系, 不看了, 你就知道这三个新方法会返回一个这样的哥们, 这哥们必须用forof来循环, 不同方法的循环结果也会不一样, 随着知识的增多自然就懂了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ZqMLg3D-1582258680175)('..')]

得到这个遍历器对象以后我们可以用for…of来循环他,

const arr = ['loki', 'thor'];
const keyResult = arr.keys();
for(let key of keyResult) {
    // 这个循环会依次输出0, 1 代表索引
    consolo.log(key); // 依次输出 0 , 1
}

const valueResult = arr.values();
for(let value of valueResult) {
    // 这个循环会依次输出loki, thor 代表数组每一项的值
    console.log(value);
}

const entriesResult = arr.entries();
for(let entry of entriesResult) {
    // 这个循环依次输出{0, 'loki'}, {1, 'thor'} 代表数组每一项索引和值的对象
   console.log(entry);
}

对于遍历器对象, 如果我们不用for…of循环则要调用它的next方法进行遍历

const arr = ['loki', 'thor'];
const keyResult = arr.keys();
console.log(keyResult.next().value); // 0
console.log(keyResult.next().value); // 1

也混个脸熟, 至于他为什么这样搞, 降到迭代器那块儿我会详细介绍, 这里你只需要知道数组上有这几个方法是干嘛的就ok

includes(value, startIndex)

关于includes这个方法呢, 如果你知道字符串上的includes方法, 那这个实例方法其实你很好理解

该方法返回一个布尔值, 表示某个数组中是否包含给定的值

该方法的第一个参数代表要检索的值

const arr = ['loki', 'thor'];
arr.includes('loki'); //返回true
arr.includes('archer'); // 返回false

该方法的第二个值表示从哪个位置开始搜索,默认值为0索引位, 而如果第二个参数小于0, 则是倒数, 而如果填的小于0的参数的绝对值大于数组长度则会按照0操作

const arr = ['loki', 'thor', 'thor'];
arr.includes('loki', 1); //false 因为索引位1的值是thor, 而thor后面无值了

arr.includes('thor', -1); // true

arr.includes('loki', -10); //true, 绝对值大于了长度所以会归0

同时inlcudes方法也支持对于NaN的检索

[NaN].includes(NaN); //true

至此, 数组上新增常用特性我也写完了, 我希望我写清楚了, 还是要不断提升自己组织语言的能力

发布了33 篇原创文章 · 获赞 11 · 访问量 2231

猜你喜欢

转载自blog.csdn.net/weixin_44238796/article/details/104425629
今日推荐