4月阅读周·你不知道的JavaScript | 用户库扩展最多的特性——Array,ES6为它增添新活力

举报
叶一一 发表于 2024/04/21 11:00:39 2024/04/21
【摘要】 背景去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。没有计划的阅读,收效甚微。新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。这个“玩法”虽然常见且板正,但是有效,已经坚持阅读三个月。4月份的阅读计划有两本,《你不知道的JavaScrip》系列迎来收尾。已读完书籍:《架构简洁之道》、《深入浅出的Node.js》、《...

背景

去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。

没有计划的阅读,收效甚微。

新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。

这个“玩法”虽然常见且板正,但是有效,已经坚持阅读三个月。

4月份的阅读计划有两本,《你不知道的JavaScrip》系列迎来收尾。

已读完书籍《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScript(中卷)》

当前阅读周书籍《你不知道的JavaScript(下卷)》

Array

静态函数Array.of(..)

Array.of(..)取代了Array(..)成为数组的推荐函数形式构造器,因为Array.of(..)并没有这个特殊的单个数字参数的问题。

var a = Array(3);
a.length; // 3
a[0]; // undefined

var b = Array.of(3);
b.length; // 1
b[0]; // 3

var c = Array.of(1, 2, 3);
c.length; // 3
c; // [1,2,3]

如果有一个回调函数需要传入的参数封装为数组,Array.of(..)可以完美解决这个需求。

另外一种情况是,如果构建Array的子类,并且想要在子类实例中创建和初始化元素,比如:

class MyCoolArray extends Array {
  sum() {
    return this.reduce(function reducer(acc, curr) {
      return acc + curr;
    }, 0);
  }
}

var x = new MyCoolArray(3);
x.length; // 3--oops!
x.sum(); // 0--oops!

var y = [3]; // Array, 而不是MyCoolArray
y.length; // 1
y.sum(); // sum不是一个函数

var z = MyCoolArray.of(3);
z.length; // 1
z.sum(); // 3

不能(简单地)只是为MyCoolArray创建一个构造器来覆盖Array父构造器的行为,因为那个构造器对于实际构造一个行为符合规范的数组值(初始化this)是必要的。MyCoolArray子类“继承来的”静态of(..)方法提供了很好的解决方案。

静态函数Array.from(..)

JavaScript中的“类(似)数组对象”是指一个有length属性,具体说是大于等于0的整数值的对象。普遍的需求就是把它们转换为真正的数组,这样就可以应用各种Array.prototype方法(map(..)、indexOf(..)等)了。

新的ES6 Array.from(..)方法都是更好理解、更优雅、更简洁的替代方法:

var arr = Array.from(arrLike);

var arrCopy = Array.from(arr);

Array.from(..) 检查第一个参数是否为iterable(参见3.1节),如果是的话,就使用迭代器来产生值并“复制”进入返回的数组。因为真正的数组有一个这些值之上的迭代器,所以会自动使用这个迭代器。

而如果你把类数组对象作为第一个参数传给Array.from(..),它的行为方式和slice()(没有参数)或者apply(..)是一样的,就是简单地按照数字命名的属性从0开始直到length值在这些值上循环。

创建数组和子类型

Array.of(..)和Array.from(..)都使用访问它们的构造器来构造数组。所以如果使用基类Array.of(..),那么得到的就是Array实例;如果使用MyCoolArray.of(..),那么得到的就是MyCoolArray实例。

原型方法copyWithin(..)

Array#copyWithin(..)是一个新的修改器方法,(包括带类型的数组在内的,参见第5章)所有数组都支持。copyWithin(..)从一个数组中复制一部分到同一个数组的另一个位置,覆盖这个位置所有原来的值。

参数是target(要复制到的索引)、start(开始复制的源索引,包括在内)以及可选的end(复制结束的不包含索引)。如果任何一个参数是负数,就被当作是相对于数组结束的相对值。

例如:

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

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

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

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

opyWithin(..)方法不会增加数组的长度。到达数组结尾复制就会停止。

原型方法fill(..)

可以通过ES6原生支持的方法Array#fill(..)用指定值完全(或部分)填充已存在的数组:

var a = Array(4).fill(undefined);
console.log(a); // [undefined, undefined, undefined, undefined]

fill(..)可选地接收参数start和end,它们指定了数组要填充的子集位置,比如:

var a = [null, null, null, null].fill(42, 1, 3);

console.log(a); // [null,42,42, null]

原型方法find(..)

ES6的find(..)和some(..)的工作方式一样,除了一旦回调返回true/真值,会返回实际的数组值:

var a = [1, 2, 3, 4, 5];
a.find(function matcher(v) {
  return v == '2';
}); // 2

a.find(function matcher(v) {
  return v == 7; // undefined
});

原型方法findIndex(..)

有些需求,需要找到匹配值的位置索引。

indexOf(..)会提供这些,但是无法控制匹配逻辑;它总是使用===严格相等。所以ES6的findIndex(..)才是解决方案:

var points = [
  { x: 10, y: 20 },
  { x: 20, y: 30 },
  { x: 30, y: 40 },
  { x: 40, y: 50 },
  { x: 50, y: 60 },
];

points.findIndex(function matcher(point) {
  return point.x % 3 == 0 && point.y % 4 == 0;
}); // 2

points.findIndex(function matcher(point) {
  return point.x % 6 == 0 && point.y % 7 == 0;
}); // -1

不要使用findIndex(..) ! = -1(这是indexOf(..)的惯用法)从搜索中得到布尔值,因为some(..)已经yield出你想要的true/false。也不要用a[ a.findIndex(..) ]来得到匹配值,因为这是find(..)所做的事。最后,如果需要严格匹配的索引值,那么使用indexOf(..);如果需要自定义匹配的索引值,那么使用findIndex(..)。

原型方法entries()、values()、keys()

从传统角度来说,Array可能不会被看作是“集合”,但是它提供了同样的迭代器方法entries()、values()和keys(),从这个意义上说,它是一个集合。

var a = [1, 2, 3];

[...a.values()]; // [1,2,3]
[...a.keys()]; // [0,1,2]
[...a.entries()]; // [ [0,1], [1,2], [2,3] ]

[...a[Symbol.iterator]()]; // [1,2,3]

就像Set一样,默认的Array迭代器和values()返回的值一样。

总结

各种JavaScript用户库扩展最多的特性之一就是数组(Array)类型。所以ES6为Array增加了一些静态函数和原型(实例)方法辅助函数也在意料之中。

Array新增了静态函数of(..)和from(..),以及像copyWithin(..)和fill(..)这样的原型函数。


作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏️ | 留言📝

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。