-
1、 基础说明及语法定义
-
1-1、基础说明
<!-- 示意:MDN原文 --> The Array.from() static method creates a new, shallow-copied Array instance from an array-like or iterable object.
- 这句话,阐述两个含义:
- 1、返回一个数组实例
- 2、入参为:一个类数组或者一个可迭代对象
- 这句话,阐述两个含义:
-
1-2、 语法定义
<!-- 示意:MDN原文 --> Array.from(arrayLike [, mapFn [, thisArg]])
- 参数说明:
- arrayLike 一个类数组或者一个可迭代对象 【必填】
- mapFn 回调函数,对返回的数组中的每个元素在数组返回前,进行操作处理(Map function to call on every element of the array.) 【非必填】
- thisArg 回调函数中的this指向
- 参数说明:
-
-
2、 重点解析
-
2-1、何为类数组?常见的那些?
- 1、objects with a length property and indexed elements【有length属性;元素可索引】
- 2、函数的arguments、Element NodeList等
-
2-2、何为可迭代对象?常见的那些?
- 1、对数组的泛化,几乎所有对象可以作为在for…of 循环中的对象【简单来说,数组就是特殊的对象,只不过key默认为index,不长显罢了】
- 2、Map and Set等
-
2-3、Array.from()的回调函数怎么理解?
- 1、
Array.from() has an optional parameter mapFn, which allows you to execute a map() function on each element of the array being created.
- 意思就是:Array.from()的回调mapFn,功能类似map()函数,遍历逐个元素;于是乎:Array.from(obj, mapFn, thisArg) === Array.from(obj).map(mapFn, thisArg) 二者的区别是:Array.from does not create an intermediate array, and mapFn only receives two arguments (element, index)【Array.from不会创建中间数组,from(obj).map会创建中间数组,一直占着内存不会销毁】
- 2、Map and Set等
- 1、
-
-
3、应用场景
-
3-1、转换字符串为数组
Array.from('foo'); // [ "f", "o", "o" ]
- 为什么这样可以,可以认为【字符串是类数组】< 字符串与数组一样,都有 length 属性以及 indexOf(…) 和 concat(…) 方法等>【关于此结论可作为额外文章进行拓展】
-
3-2、将Set对象转换为数组
const set = new Set(['foo', 'bar', 'baz', 'foo']); Array.from(set); // [ "foo", "bar", "baz" ] <!-- 当然你也可以用ES6的简单写法 --> [ ... new Set(['foo', 'bar', 'baz', 'foo'])]
-
3-3、将Map对象转换为数组
const map = new Map([[1, 2], [2, 4], [4, 8]]); Array.from(map); // [[1, 2], [2, 4], [4, 8]] const mapper = new Map([['1', 'a'], ['2', 'b']]); Array.from(mapper.values()); // ['a', 'b']; Array.from(mapper.keys()); // ['1', '2'];
-
3-4、将Element NodeList转换为数组
// Create an array based on a property of DOM Elements const images = document.getElementsByTagName('img'); const sources = Array.from(images, image => image.src); const insecureSources = sources.filter(link => link.startsWith('http://')); //这里的getElementsByTagName得到的images就是个类数组,同样我们可以很自然的想到通过querySelectorAll()得到的集合也是类数组
-
3-5、将函数arguments转换为数组
function f() { return Array.from(arguments); } f(1, 2, 3); // [ 1, 2, 3 ]
-
3-6、填充数组【这里不讨论Array.fill()】
-
3-6-1、形式一:
<!-- 用索引填充 --> Array.from({length: 5}, (v, i) => i); <!-- 用指定的值填充 --> Array.from({length: 5}, (v, i) => 6666);
- {length: 5}得到的是一个可迭代的对象,Array.from处理后就是个数组【长度为5,单个元素每个都为undefined】,然后在经过Array.from的回调mapFn处理,此时v为undefined,i为索引
-
3-6-2、形式二:【拓展】
<!-- 用指定的值填充 --> Array(10).fill(666); <!-- map填充会失效 --> Array(3).map((item,index)=>index); // 这个不会得到[0,1,2],而会得到[empty,empty,empty]
-
这里要要特别注意 Array(10)返回的是一个长度10且每个元素为undefined的数组,而不是[10] 【关于Array函数具体如何使用可自行拓展】
-
3-6-3、将只有一个元素的组织快速复制n倍:【思考】
var a = [3] var b = Array.from({length: 10}, (v, i) => a[0]);
-
-
3-7、克隆数组
- 代码实现:
const arr = [1, 2, 3, 4, 5] const arrCopy = Array.from(arr)
- 注意这个是浅拷贝,Why?【Ex如下:】
<!-- 一维度操作 --> var a = [1, 2, 3, [4, 5, 6]] var b = a var c = Array.from(a) a.push(7) // a: [1, 2, 3, [4, 5, 6], 7] // b: [1, 2, 3, [4, 5, 6], 7] // c: [1, 2, 3, [4, 5, 6]] //这个没有7 <!-- 二维度操作 --> var a = [1, 2, 3, [4, 5, 6]] var b = a var c = Array.from(a) a[3].push(7) // a: [1, 2, 3, [4, 5, 6, 7]] // b: [1, 2, 3, [4, 5, 6, 7]] // c: [1, 2, 3, [4, 5, 6, 7]]
- 代码实现:
-
3-8、生产范围数组
-
3-8-1 生产范围数字:
// Sequence generator function (commonly referred to as "range", e.g. Clojure, PHP etc) const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step)); // Generate numbers range 0..4 range(0, 4, 1); // [0, 1, 2, 3, 4] // Generate numbers range 1..10 with step of 2 range(1, 10, 2); // [1, 3, 5, 7, 9]
-
3-8-2 生产范围字母:
// Generate the alphabet using Array.from making use of it being ordered as a sequence range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x)); // ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
-
-
3-9、结合第三个参数操作回调函数
- 第三个参数可以指定第二个回调函数的this值。那么,Array.from既有类似 map的功能,也有类似 bind的功能,可以给定this
- 代码实现:
const arr = [1, 2, 3, 4, 5, 6]; const newArr = Array.from(arr, function (item, i) { return item + this.value }, { value: 3 }) // [4, 5, 6, 7, 8, 9]
-
-
4、思考:写了这些应用场景,有几点还是可以思考的:
- 你能定这么多的应用场景,并不是这个功能有多复杂,而是这个api创建的数组实例来源于【类数组和可迭代两个方向】,这两个方向太广了,可罗列的也比较多
- 在知识梳理中我们我遇到了几个比较有意思的点,可作为额外知识点,继续梳理拓展终结:
- 字符串是类数组
- Array()入参一个参数为什么得到的和预想的不一样,入参多个和预想的却又一样
- Array(n).map()时,map在遍历empty时为什么不会生效
- 深拷贝和浅拷贝如何区分【是不是可以简单的理解,深拷贝通过递归就能实现】
-
5、 参考文献