admin管理员组

文章数量:1587993

 

 

前言

科普 JavaScript,揭开 JavaScript 神秘面纱,直击 JavaScript 灵魂。此系列文章适合任何人阅读。

本文章内容为:

  1. 标准化数组。
  2. 数组与数组容器。
  3. ECMAScript 规范中 Array API 讲解。
  4. 如果你想用 Array,而又不想学 API 的办法。
  5. 标准规范以外的 Array API 扩展。
  6. V8 引擎对 Array 的处理和优化。
  7. 数据本质。

Array 作为 JavaScript 语言除 Object 外唯一的复杂数据结构,彻底掌握它非常有必要。

这篇文章的初衷,就是讲透数组以及 JavaScript 中 Array 的概念、作用、所有 API 和便捷用法。最终可以达到融会贯通,在无数用法中找到最正确的那一种,让 Array 操作变成得心应手。

千老师写完这篇文章的时候,已经是 2019 年年底,截至文章完成,这些是最新的 ECMAScript 规范、JavaScript 版 v8 的 Array、C++版 V8 的 Array、V8 Array 运行时。

温馨提示:由于文章篇幅过长,我觉得你不太可能坚持一次看完。所以建议你先收藏。如果遇到看不懂的内容,或者不想看的内容,可以快进或者选择性观看。

标准数组:灵魂四问-从数组源头问起

要学习一个东西,最佳方式就是不断地抛出问题,通过对问题的探索,一步一步拨开迷雾,寻找真相。

上面这句话是千老师写的,不具有权威性。所以千老师先提出一个问题,来证明这个观点是正确的。

提问到底有多重要?这是个问题。这里千老师借鉴几位大神的名言解释一下这个问题:

  1. 创造始于问题,有了问题才会思考,有了思考,才有解决问题的方法,才有找到独立思路的可能。—— 陶行知

  2. 提出正确的问题,往往等于解决了问题的大半。——海森堡

  3. 生活的智慧大概就在于逢事都问个为什么。——巴尔扎克

  4. 有教养的头脑的第一个标志就是善于提问。——普列汉诺夫

  5. 一个聪明人,永远会发问。——著名程序员千老师

  6. 善问者,如攻坚木,先其易者,后其节目。 ——《礼记·学记》

  7. 好问则裕,自用则小。——《尚书·仲虺之诰》

  8. 敏而好学,不耻下问。——《论语·公冶长》

  9. 君子之学必好问,问与学,相辅而行者也。非学,无以致疑;非问,无以广识。——刘开

  10. 知识的问题是一个科学问题,来不得半点虚伪和骄傲,决定的需要的倒是其反面——诚实和谦逊的态度。——毛爷爷

好,千老师随便一整理,就整理出十个解释问题为什么重要的原因,连伟大的开国领袖毛爷爷都喜欢问题,非常棒。但这是一篇讲解程序的文章,不是学习名言警句的文章,所以大家收一收。只要明白”带着问题去学习效率是非常高的“这个道理就足够了。下面转入正题。

1.数组是什么?

现在千老师先抛出第一个正式的问题,数组到底是个啥?

这个问题好像很简单哎,可事实真的是这样吗?不服的话,你可以先把你的答案说出来,等看完本篇文章后,再来对比,是否和原来的答案一致。

这里千老师偷个懒,拿出 wiki 百科对数组的解释:

数组数据结构(英语:array data structure),简称数组(英语:Array),是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的索引(index)可以计算出该元素对应的存储地址。

从这句非常官方的解释里面,千老师找到几个关键的点:相同类型的元素、连续的内存、索引

标准数组,是一定要符和上面这三个条件的。其实还有一个条件,wiki 上面没体现出来,就是固定大小

数组的设计,最早是出自 C 语言。在后来出现的编程语言中,大都效仿了 C 语言的数组设计。比如 C++、Java、Go 等等。

从这里开始,千老师就要推翻你传统思维中的JavaScript数组概念。只有推翻,才能反向验证。只有打破,才能破镜重圆。

2.数组为什么有类型?

先拿 Java 的标准数组举例。为什么要拿 Java 举例呢?因为 JavaScript 中没有“标准数组”。

int arr[] = new int[3]; /*创建一个长度为3的int类型数组*/
arr[0] = 1; // 给下标0 赋值
arr[1] = 2; // 给下标1 赋值
arr[2] = 3; // 给下标2 赋值

我们在 Java 中来一点在 JavaScript 的常规操作。

arr[2] = "3"; // error: incompatible types: String cannot be converted to int

看,Java 竟然报错了!这个错误的意思是: int 类型的数组,不兼容 String 类型的元素。

如果你一直在使用 JavaScript,而没用过其它强类型编程语言,你肯定觉得这很神奇。数组竟然还可以有类型?赶紧提出第二个问题:数组为什么有类型?

是的,数组有类型,而且数组有类型还有原因,后面千老师再说为什么数组会有类型。

3.数组的长度为什么不可以改变?

再来一个 JavaScript 的常规操作。

arr[3] = 1;// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

Java 竟然又报错了!如果你一直在使用 JavaScript,看到这里估计你已经惊呆了。这个错误的意思是:索引超过了数组的最大界限。

这个现象又说明一个问题:数组的长度一旦确定,就不会再发生改变。

千老师替你提出第三个问题:数组的长度为什么不可以改变?

看到这里你肯定会想,标准数组这么多限制,用起来未免也太麻烦了吧?

4.数组的下标为什么是从 0 开始的?

最后,千老师再补充一个已经被大家习以为常,甚至已经被忽略掉的的问题:数组的下标为什么是从 0 开始的?

解答时刻

第二题:数组为什么有类型?

因为数组的寻址公式:array[i]Address = headAddress + i * dataTypeSize

啥玩意是寻址公式?

寻址方式就是处理器根据指令中给出的地址信息来寻找有效地址的方式,是确定本条指令的数据地址以及下一条要执行的指令地址的方法。

我翻译一下,就是在内存块中找到这个变量的方法。

这里涉及到一些计算机原理和数据结构与算法的知识,因为本篇文章的主要内容是讲解 JavaScript 的 Array 相关知识,所以千老师不会展开讲这些问题。不过考虑到很多人不是科班出身,或者科班出身没认真学过计算机原理。千老师还是略微讲讲寻址是个啥,有啥用。

首先内存地址是个什么东西?内存地址长这样:0x12345678。在编程语言中,我们创建的变量,都被存到了内存中,你可以理解成一个hash,或者是 ECMAScript 中的 object0x12345678 是 key,你创建的变量名和变量的值是 value。而寻址,就是找到内存地址,把内存地址中的 value 拿出来。换成 JavaScript 表达式大概是这样:Memory["0x12345678"]

大概明白了寻址。接下来再看一下创建数组的过程:

创建数组,就是向内存申请一块固定大小的空间。这块空间有多大呢?根据数组的长度和数组的数据类型来得到的。

比如上面的例子。int 类型是 4 个字节,长度是 3 的 int 类型数组,就需要 3*4=12 个字节的内存空间。

一旦申请成功,CPU 就会把这块空间锁住。并且记录一个这块空间的内存首地址。也就是上面那个公式的 headAddress。

在之后的访问中,就可以通过这个公式来快速寻址。

这解释通了 数组为什么有类型。

第三题:数组的长度为什么不可以改变?

因为数组的内存是连续分配的,如果数组的长度发生改变,就意味着数组的占用内存空间也发生改变。而数组原空间后面的空间有可能被其它值所占用了,这也是处于安全性的考虑,所以无法改变。

第四题:数组的下标为什么是从 0 开始的?

如果下标从 1 开始,按照人类十进制的逻辑非常值观,但对于 CPU 而言,就麻烦了。数组的寻址公式就要改成:array[i]Address = headAddress + (i-1) * dataTypeSize,这样每次对数组的操作,CPU 都会平白无故多一次减法运算,对性能不利。

看到这,你应该明白,我们在 JavaScript 中日常使用的 Array 类型,并不是“标准数组”。同时也明白了,标准化数组的特征。

数组容器:分析一下 Java 中的 ArrayList 和 ECMAScript 中的 Array

通过上面的四道自问自答,相信你也明白了数组设计成这样的苦衷。真的是让我们一言难尽啊,但是又不得不尽。

屏蔽细节的数组容器

如果一直在数组的这么多限制下编程,很多人肯定会被逼疯。所以聪明的程序员们发明了一种屏蔽底层数组操作的数组容器。

比如 Java 中出镜率非常高的 ArrayList。而 ECMAScript 中的 Array 类型,同样也是如此。

这类容器有什么好处呢?

我们来操作一下,就能体验到。

还是拿 Java 举例。为什么还要拿 Java 举例呢?因为只有通过对比才能引起你的深思。

ArrayList arr = new ArrayList(1);// 创建一个初始长度为 1 的数组
arr.add(1);// 加 1 个数据
arr.add("2");// 再加 1 个 String 类型的数据
System.out.println(arr);// 没有问题,正常输出 [1, 2]

可以看到 Java 的 ArrayList 解决了两个重要的问题。

1.可以存储不同类型的数据。

2.可以自动扩容。

那它是怎么实现的呢?这块内容虽然也不属于本篇文章的范围内。但千老师还是忍不住简单说一下。

1.如何实现可以存储不同类型的数据?

不论是 JavaScript 还是 Java,基本的内存都分为堆内存 Head 和栈内存 Stack。因为基本数据类型,(不好意思,打断一下,千老师在这里提个问题?2019 年,ECMAScript 有几种基本数据类型?)都是存到栈内存中的。为什么要存到栈内存中呢?这又是个很好的问题。你可以先猜一下。因为基本数据类型都是固定的值,既然值都是固定的,那么大小也是固定的。说到这里,千老师再来提个问题:在 ECMAScript 中,一个 3 个字符的 String 类型变量占几个字节?你看,**问题无处不在,就看你有没有发现问题的眼睛。**这也算是一个小彩蛋,在 ECMAScript2015 以前,ECMAScript5.0 中,采用 Unicode 编码,中文字符和英文字符都是占 2 个字节大小。所以上面问题的答案就是 2*3=6 个字节。但 ECMAScript6 以后,答案不同了。因为编码换了,换成 utf8 了。这里千老师再提一个问题,unicode 和 utf8 有什么不同?嘿嘿,是不是快崩溃了?utf8 是使用 1 到 4 个字节不等的长度进行编码的。因为老外发现世界上大多数网站都是英文语言的网站,而其他语言(在老外眼里,除了英语,其他统称为其他语言)的网站占比很少。所以 utf8 中,英文字符只占 1 个字节,而像其它语言,比如中文,就占了 3 个字节。所以上面的题目还缺少一个条件,还要明确 3 个字符都是哪国语言才能给出正确答案。扯远了,我们赶紧收回来,继续讲堆和栈的问题。既然基本数据类型的大小都是固定的,那么放在栈里面就很好知道数组总共的大小,就可以申请到连续的内存块。那么存储引用类型的变量时,ECMAScript 是怎么做的呢?聪明的你肯定猜到了,那就是存到堆内存中了。准确的说,是把变量的数据存到堆内存中,而栈内存仍然会存一个东西,那就是堆内存的内存指针,也就是我们常说的引用。这样就解释通了,数组容器怎么存储不同类型数据的。

关于堆内存和栈内存的详细介绍,就不展开说了。

如果想详细了解这部分内容,推荐查阅如果想详细了解这部分内容,推荐查阅《JavaScript高级程序设计(第3版)》第四章。

堆栈内存这部分内容并不是可以被单独拿出来的一个概念,如果想彻底学好,就要有系统的去学,才可以真正理解。基础不好的同学,推荐去读《深入理解计算机系统(原书第3版)》。这本书在豆瓣上获得了9.8的高分。但实际上,它并不是一本传统意义上“深入”的书。而是讲解“计算机底层”整体脉络的书。所以它是一本广度非常高的书,非常适合完善个人的计算机知识体系。

2.如何实现自动扩容?

ArrayList 无参构造,会默认创建一个容量为 10 的数组。每次添加元素,都会检查容量是否够用,如果不够用,在内部创建一个新的数组,该数组的容量为原数组容量的 1.5 倍。再将原数组的数据都搬移到新数组中去。如果新数组的容量还是不够,就会直接创建一个符和所需容量的数组。

这么干没有什么太大的问题,最大的问题就是性能会受到一定的影响。另一个是和 JavaScript 无关的问题,线程安全问题。因为创建新数组,迁移数据这个过程需要一定的时间。Java 这种多线程的语言,如果在这个过程中另一个线程再去访问这个 ArrayList,就会出问题。

为什么要解释 Java 的 ArrayList 呢?因为千老师只看过 ArrayList 的实现源码,很尴尬。没看过 JavaScript 的同学,如果你感兴趣,可以去文章开头我挂的那个 V8 源码链接看看 ECMAScript 是怎么干的。我猜它的实现和 ArrayList 是一个原理,你看完可以回来告诉千老师一下,看千老师猜的对不对。虽然千老师没仔细看过 V8 的实现,但请不要质疑千老师对 JavaScript 的专业程度,也不要胡乱猜测千老师是搞 Java 的。在这里强调一下,千老师是正儿八经的 JavaScript 程序员,从始至终都是以 JavaScript 作为第一编程语言。哦不,现在是 TypeScript。

不论是 Java 的 JDK 还是 ECMAScript 的 V8,归根结底的实现还是 C。所以千老师在这里建议大家:一定不要想不开去看 C 的源码。

总结一下:凡是被程序员用起来不爽的东西,总会被各种方式改造。直到变成大伙儿都喜欢的样子为止。如果你想彻底搞明白一件事情,就必须从源头找起,看看她的原貌,再看看她化妆、整容的全过程,最后看她是如何一步一步蜕茧成蝶。

EAMCAScript 中数组的本质,Array 到底是什么?

这是 JavaScript 中最常见的一个数组。

let arr = [
  "h",
  9,
  true,
  null,
  undefined,
  _ => _,
  { a: "b" },
  [1, 2],
  Symbol(1),
  2n ** 1n,
  Infinity,
  NaN,
  globalThis,
  Error("hi"),
  Math.LN10,
  Date(),
  /\w+/i,
  new Map([["k1", "v1"]]),
  new Set([1, 2]),
  new DataView(new ArrayBuffer(16)),
  new Promise((resolve, reject) => {}),
];

有点乱,但无伤大雅。可以看到,数组就像是一个巨大的黑洞,可以存放 ECMAScript 中的任何东西。变量,任何数据类型的数据,包括数组本身,都可以。这一点让我想起了QQ空间里面经常出现的游戏广告,山海经,吞食天地、无所不能吞的鲲。

为什么可以这么干呢?

因为和上面介绍的一样,Array 存储基本类型时,存储的是值。存储引用类型时,存储的是内存引用。

ECMAScript 中的 Array,完全不像传统数组。因为它是个对象。

由于 ECMAScript 是一门弱类型语言,没有类型系统的强制约束,任何类型的变量都是可以被挂在上任何属性的。数组也不例外。

给一个对象添加一个属性。

let obj = {};
obj["0"] = 1;

给一个数组添加一个元素。

let arr = [];
arr["0"] = 1;

从一个对象中取值。

obj["0"];

从一个数组中取值。

arr["0"];

再举个例子,如下数组:

["dog", "pig", "cat"];

等价于如下对象:

{
    "0": "dog",
    "1": "pig",
    "2": "cat",
    "length": 3
}

在某种程度上来看,Array 和 Object 没有太明显的区别。甚至激进点讲,Array 和 Object 本质上是一回事。(这句话千老师不承担任何法律责任,就是随便说说)

在 JavaScript 中,你完全可以把数组理解成是对象的一种高阶实现。

JavaScript 中,Array 到底有多么自由呢?可以存储不同类型的值,可以通过负索引访问,下标可以超过原始声明范围,甚至可以通过非数字索引。虽然 Array 和数组格格不入,但它毕竟还叫作数组,毕竟还是和数组有相似之处的,比如 Array 仍然是以"0"作为起始下标的。(这是一个冷笑话。)

所以,不要再拿传统的数组概念来定义 ECMAScript 的 Array。因为它只是长的像而已。

硬核实战:ECMAScript 中 Array 的 API

该说的不该说的,该问的不该问的,上面都讲完了。

接下来,就让我们进入本文最后一部分,从所有的 API 中感受 Array 的强大。

在千老师写这篇文章之前,已经有很多人写过类似的优秀文章了,比如 MDN

不过千老师保证比这些人讲的更加生动形象,通俗易懂,风趣十足,别具一格。带你深入……浅出 Array 的世界。

虽然这篇文章出现的时间非常晚了,但是没有办法。千老师相信后浪能把前浪拍在沙滩上,使劲蹂躏。

目前标准规范中,Array 的所有的属性和方法加起来,有足足 36 个之多,实在是令人汗颜。

下面先从创建数组一步步讲起。

创建数组

创造的神秘,有如夜间的黑暗,是伟大的。而知识的幻影,不过如晨间之物。——泰戈尔

常规且标准的创建数组的方式有 3 种。

1.直接使用字面量[]创建

let arr1 = [0, 1, 2];

2.使用 Array 构造函数创建

let arr1 = new Array(0, 1, 2);

3.调用 Array 内置方法创建

let arr1 = Array(0, 1, 2);

异同之处:

方法 2 和方法 3 的作用是相同的,因为在 Array 函数实现内部判断了 this 指针。

new Array 和 Array有两种用法,在仅传递 1 个参数的时候,创建的不是存储该值的数组,而是创建一个值为参数个数的 undefined 元素。

let arr1 = [10]; // [10]
let arr2 = Array(10); // [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]

不常规且不标准的创建数组的方式也有。具体几种千老师也没统计过,因为这不是很重要。最常见的不常规且不标准用法就是from,这里不剧透了,可以继续朝下看。

访问数组

真理是生活,你不应当从你的头脑里去寻找。——罗曼·罗兰

说完创建数组,接着看看怎么访问数组。

访问数组其实很简单,通过方括号[]就可以了。

let arr1 = [0, 1, 2];
arr1[0]; // 0

我们习惯写一个number类型的参数放在方括号里,因为我们知道这个数字是元素的数组下标,数组下标是一个number类型的值,很正常对吧。但其实不然,上面例子中的arr1[0]在真正被执行的时候,会变成arr1['0']。会经过toString方法隐式转换。为什么会这样呢?因为ECMAScript规范规定了。这里先卖个关子,暂且不讲,感兴趣的同学可以自己去查一查。虽然会有个隐式转换过程,但一般正常一点的程序员是不会直接使用带引号的写法的。

实例属性

constructor

无父何怙,无母何恃?——《诗经》

在 ECMAScript 中,除了 null 和 undefined 外,几乎所有东西都有这个属性。表明了该对象是由谁构造出来的。

通常用到这个属性的场景,就是在判断对象是不是 Array 的实例。

let arr = [];
arr.constructor === Array; // true

但是很遗憾,这个属性是可写的。可写意味着这个方式并不能百分之百辨别出一个对象是否是 Array 的实例。

let arr = [];
arr.constructor = String;
arr.constructor === Array; // false
arr.constructor === String; // true

你看,本来是由 Array 生出来的变量 arr,通过一行代码,就改认 String 做父辈了。再次证实了,Array 的实例,都是有钱便是爹,有奶便是娘的货色。

再看个例子。

let str = "";
str.constructor = Array;
str.constructor === Array; // false
str.constructor === String; // true

str 和 arr 有着鲜明的差别。str 是孝子啊,亲爹就是亲爹,有钱也不管用。

其实除了 String,其他几种基本类型的 constructor 属性都是可以改,但是改了没起作用。

为什么没起作用呢?因为这涉及到开装箱的操作。

所以这里千老师出一道题:原始类型为什么可以调用方法和访问属性?

搞明白这道题,你就能明白上面这个现象是为什么了。这不算是 Array 的知识点,算是知识扩展吧。

你答上来上面这题,千老师再出一道题,通过构造函数创建出来的原始类型和用字面量创建出来的原始类型,有什么区别?

length

尺有所短,寸有所长

代表数组元素的个数。

let arr = [0, 1, 2];
arr.length; // 3

这个属性好像很简单,没什么好讲的对吧?

其实还真有点东西可以给大家讲讲。

length最大的妙用,就是直接改变length属性可以删除元素或增加元素。

let arr = [0, 1, 2];
arr.length = 2;
console.log(arr); // [0, 1]
arr.length = 5;
console.log(arr); // [0, 1, empty × 3]

看到这里,又出现一个empty,这是个啥?大家知道吗?

empty是一个和undefined很像,但又有一点细微区别的东西。

可以做个实验。

console.log(arr[3] === undefined); // true

在这个实验里,我们发现empty是全等于undefined的。

但是它们还存在一定区别。比如下面的实验。

arr.indexOf(undefined); // -1

arr.filter(item => item === undefined); // []
arr.forEach(item => {
  console.log(item);
}); // 1, 2

indexOffilterforEach都是不认为empty等于undefined的。会自动忽略掉empty

再做两个实验。

arr.includes(undefined); // true

arr.map(item => typeof item); // ["number", "number", empty × 3]

但是includes很很神奇的认为empty就是和undefined一个概念。而在map中,则会自动保留empty的空槽。

这里并不是说typeof不好使,而是typeof item这条语句,在碰到empty时直接跳过了,没有执行。

为了证实这个事,再单独拿万能的 typeof操作符做个实验。

console.log(typeof arr[3]); // undefined

这到底是个怎么回事呢?千老师在 ECMAScript6 的文档中发现,明确规定了empty就是等于undefined的,在任何情况下都应该这样对待empty。千老师又去翻了下 V8 源码,果然在 V8 源码中找到了关于empty的描述,原来它是一个空的对象引用。

空的对象引用这个东西,在 ECMAScript 中应该是什么类型呢?ECMAScript 一共就那么几个类型,按道理说,它不符合任何类型啊。

没办法,undefined这个尴尬的数据类型就很莫名其妙地、很委屈地成为了empty的背锅侠。

方法

from

士不可以不弘毅,任重而道远

从 ECMAScript1 开始,就一直有一个令人头疼的问题(当然令人头疼的问题远不止一个,我这里说有一个,并不是说只有一个,这里必须重点提醒一下。),ECMAScript 中充斥着大量的类数组对象。它们像数组,但又不是数组。最典型的像是arguments对象和getElementsByTagName

为了解决这个问题,很多类库都有自己的解决方案,如大名鼎鼎的上古时代霸主级 JavaScript 库jQuery,就有makeArray这个方法。

随着日新月异的科技演变,经过无数 JavaScript 爱好者努力拼搏,追求奉献,经历了二十多年的沧海桑田,白云苍狗。ECMAScript 终于等来了from这个自己的超级 API。有了这个 API 以后,ECMAScript 再也不需要像makeArray这类第三方解决方案了。ECMAScript 站起来了!说到这,千老师不禁想起了那些曾为 ECMAScript 的自由,开放,扩展,交融而抛头颅洒热血的大神们,是他们,在 ECMAScript 遭受屈辱的时刻挺身而出,以力挽狂澜之势救黎民于苦难。在 ECMAScript 发展过程中,千老师看到了, ECMAScripter 们,敢于直面惨淡的人生,敢于正视淋漓的鲜血,在JavaCC++,甚至PHP的鄙视下,在所有人嘴里的“不就是个脚本语言吗?”的侮辱中,我们以燃烧的激情和鲜血凝聚成精神的火炬,点燃了未来。

扯远了,我们收回来。吹了那么多,赶紧继续学习一下from的使用吧。

作用:从类数组对象或可迭代对象中创建一个新的数组。

语法:Array.from(arrayLike[, mapFn[, thisArg]])

参数:

  • arrayLike:想要转换成数组的伪数组对象或可迭代对象。

  • **mapFn **(可选) :如果指定了该参数,新数组中的每个元素会执行该回调函数。

  • **thisArg **(可选):执行回调函数 mapFn 时 this 对象。

返回值:新的数组实例。

支持 String、Set、Map、arguments 等类型。

还支持通过函数来创建。

// String 转 Array
let arr1 = Array.from("123"); // ["1", "2", "3"]
// Set 转 Array
let arr2 = Array.from(new Set([1, 2, 3])); // [1, 2, 3]
// Map 转 Array
let arr3 = Array.from(
  new Map([
    [1, 1],
    [2, 2],
    [3, 3],
  ])
); // [[1, 1], [2, 2], [3, 3]]
// MapKey 转 Array
let arr4 = Array.from(
  new Map([
    [1, 1],
    [2, 2],
    [3, 3],
  ]).keys()
); // [1, 2, 3]
// MapValue 转 Array
let arr5 = Array.from(
  new Map([
    [1, 1],
    [2, 2],
    [3, 3],
  ]).values()
); // [1, 2, 3]
// arguments 转 Array
function fn() {
  return Array.from(arguments);
}
fn(1, 2, 3); // [1, 2, 3]

除了转换这个作用以外,喜欢探索的程序员又发现了另外几个神奇的用法。

1.用来创建数组。

let arr = Array.from({ length: 3 });
console.log(arr); // [undefined, undefined, undefined]

from方法很不错,并没有创建 3 个empty出来。看来 ECMAScript6 的规范还是挺好使的,至少 Chrome 听他的。

还可以在这里加一些逻辑,比如生成某个范围的数字数组。

let arr = Array.f

本文标签: 你真JavaScriptArray