Array.from使用技巧
es6中数组扩展了新的方法;Array.form
,我们看看有什么好玩的用处。
# Array.form 介绍
Array.from()
方法从一个类数组或可迭代对象创建一个新的,浅拷贝的数组实例。
Array.from(arrayLike[, mapFn[, thisArg]])
第一个参数必传,为类数组;第二个参数可选,是一个map函数,将逐一数组元素进行处理并返回。
# arrayLike-类数组
JavaScript 类数组对象的定义:
- 可以通过索引访问元素,并且拥有 length 属性;
- 没有数组的其他方法,例如 push , forEach , indexOf 等。
举例说明:字符串 abc
,对象 {'1':1212,'2':1212,length:6}
都是类数组。
《javascript权威指南》上给出了代码用来判断一个对象是否属于“类数组”。
// Determine if o is an array-like object.
// Strings and functions have numeric length properties, but are
// excluded by the typeof test. In client-side JavaScript, DOM text
// nodes have a numeric length property, and may need to be excluded
// with an additional o.nodeType != 3 test.
function isArrayLike(o) {
if (o && // o is not null, undefined, etc.
typeof o === 'object' && // o is an object
isFinite(o.length) && // o.length is a finite number
o.length >= 0 && // o.length is non-negative
o.length===Math.floor(o.length) && // o.length is an integer
o.length < 4294967296) // o.length < 2^32
return true; // Then o is array-like
else
return false; // Otherwise it is not
}
lodash库也有相关判断方法 (opens new window)
_.isArrayLike([1, 2, 3]);
// => true
_.isArrayLike(document.body.children);
// => true
_.isArrayLike('abc');
// => true
_.isArrayLike(_.noop);
// => false
# 第二个参数
Array.from() 方法有一个可选参数 mapFn,让你可以在最后生成的数组上再执行一次 map 方法后再返回。利用这个参数我们可以做一些技巧性操作。
# 技巧运用
# nodeList转数组
ArrayLike对象指具有数组某些行为的对象,具体表现就是具有length属性。 有两种最常见的有两种:DOM中的NodeList和函数中的arguments。
通常使用for循环
或者[...nodeList]
运算就就可以转换。
当然也可以这样
const args = [].slice.call(arguments);
const imgs = [].slice.call(document.querySelectorAll('img'));
现在又多了一种方法,可以这样
const args = Array.from(arguments);
const imgs = Array.from(document.querySelectorAll('img'));
arguments 同理
function fun() {
return Array.from(arguments);
}
fun(1, 2, 3);
// [ 1, 2, 3 ]
# 字符串转数组
同样的字符串也多了一种数组转换的方式
function fun(str) {
return Array.from(str);
}
fun('abcd');
// [ a, b, c ,d ]
# Map和Set转数组
从set生成数组,用此方法可以数组去重复。
const set = new Set(['foo', 'bar', 'baz', 'foo']);
Array.from(set);
// [ "foo", "bar", "baz" ]
从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'];
# 填充对象
Array.from({length:20},()=>{return {}});
# 填充随机数数组
Array.from({ length: 5 }, Math.random)
// [0.3160631607676865, 0.5155864876234266, 0.3654605814267633, 0.7502778910019559, 0.2978960060832099]
Array.from({ length: 5 }, Math.random).map(x=>parseInt(10*x))
// [8, 5, 7, 1, 2]
# 填充序列数组
Array.from({length:20},(v,i)=>i); // 可以这样
Array.from(Array(20).keys()); // 可以这样
[...Array(20).keys()] // 还可以这样,貌似更简洁
// 三种效果一致
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
# 填充指定范围序列数组
稍加改造,可以生成指定范围的序列数组
const range = (start, stop, step=1) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
range(56,100,3)
// [56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98]
// 生成奇数
range(1, 10, 2);
// [1, 3, 5, 7, 9]
// 字母序列
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"]
# 兼容性
下面是caniuse的兼容性列表,兼容性还是不错的。
# polyfill
由于es6是新特性旧项目万一有兼容性问题,可以添加polyfill (opens new window)替代方法