from 方法用于将两类对象转为真正的数组:相似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)。javascript
Array.from(arrayLike[, mapFn[, thisArg]])
arrayLike
想要转换成数组的伪数组对象或可迭代对象。java
mapFn (可选参数)
若是指定了该参数,新数组中的每一个元素会执行该回调函数。es6
thisArg (可选参数)
可选参数,执行回调函数 mapFn
时 this
对象。数组
一个新的数组实例浏览器
将字符串转化为数组。数据结构
Array.from('hello') // [ 'h', 'e', 'l', 'l', 'o' ]
传参为数组类型对象时原样输出。函数
Array.from([1, 2, 3]) // [ 1, 2, 3 ]
将 Set 对象转换为数组。this
Array.from(new Set(['a', 'b'])) // [ 'a', 'b' ]
传参为无 length 属性的 Object。prototype
Array.from({ 0: 'a', 1: 'b', 2: 'c' }) // []
传参为有 length 属性的 Object。code
Array.from({ 0: 'a', 1: 'b', 2: 'c', length: 3 }) // [ 'a', 'b', 'c' ]
经过对比能够得知一个结论:
任何 有length
属性的对象,均可以经过from
方法转为数组。
与此同时,Spread 运算符 ...
也能够将实现了遍历器接口 Symbol.iterator
的数据结构转为数组。
var o = { 0: 'a', 1: 'b', 2: 'c', length: 3 } Array.from(o) // [ 'a', 'b', 'c' ] [...o] // TypeError
经过上述?能够说明 ...
的局限性。对象赋值了 length
属性,但并未实现 Symbol.iterator
,因此报错。
再举个比较实用的场景,罗列一下类数组对象 arguments
转换为数组的几种方式。(类数组对象实现了遍历器接口Symbol.iterator
,它有length
属性,数据结构和数组很像,可是它不是数组。具体的能够参考文章《Array-like Objects in JavaScript》)。
ES5
function foo() { [].slice.call(arguments); }
ES6 Array.from
function foo() { Array.from(arguments); // [ 'a', 'b', 'c' ] }
ES6 Spread Operator ...
function foo() { [...arguments]; // [ 'a', 'b', 'c' ] }
将对象转换为数组的几种形式。
// key值为整形 var o = { 0: 'a', 1: 'b', 2: 'c', length: 3 } Array.from(o) // [ 'a', 'b', 'c' ] // key值为只包含数字内容的字符串 var o = { '0': 'a', '1': 'b', '2': 'c', length: 3 } console.log(Array.from(o)); // [ 'a', 'b', 'c' ] // key值不从0起 var o = { 1: 'a', 2: 'b', 3: 'c', length: 3 } Array.from(o) // [ undefined, 'a', 'b' ] // key值为不能转化为数字的字符串 var o = { a: 'a', b: 'b', c: 'c', length: 3 } Array.from(o) // [ undefined, undefined, undefined ] // key值为包含数字和字符混杂的形式 var o = { '0a': 'a', '1': 'b', '2': 'c', length: 3 } console.log(Array.from(o)); // [ undefined, 'b', 'c' ] // key值既有字符又有数字 var o = { a: 'a', 2: 'b', c: 'c', length: 3 } console.log(Array.from(o)); // [ undefined, undefined, 'b' ] // key值既有字符又有数字而且length属性大于对象除length属性外定义属性的个数 var o = { a: 'a', 2: 'b', c: 'c', length: 4 } Array.from(o) // [ undefined, undefined, 'b', undefined ]
from
是经过key做为下标而且参照 length
属性大小来填充元素的。当没有合适的元素插入时就会插入 undefined
补位。
相似Array.prototype.map()
的用法
Array.from(arrayLike, x => x * x); // 等同于 Array.from(arrayLike).map(x => x * x); Array.from([1, 2, 3], (x) => x * x) // [ 1, 4, 9 ]
下面的例子将数组中布尔值为false的成员转为0。
Array.from([1, , 2, , 3], (n) => n || 0) // [1, 0, 2, 0, 3]
Array.from()能够将各类值转为真正的数组,而且还提供map功能。这实际上意味着,你能够在数组里造出任何想要的值。
Array.from({ length: 2 }, () => 'jack') // ['jack', 'jack']
上面代码中,Array.from的第一个参数指定了第二个参数运行的次数。这种特性可让该方法的用法变得很是灵活。
Array.from()
的另外一个应用是,将字符串转为数组,而后返回字符串的长度。由于它能正确处理各类Unicode字符,能够避免JavaScript将大于uFFFF的Unicode字符(超纲字),算做两个字符的bug。
function countSymbols(string) { return Array.from(string).length; }
对于尚未部署该方法的浏览器,可使用Array.prototype.slice
方法替代。
const toArray = (() => Array.from ? Array.from : obj => Array.prototype.slice.call(obj))();
写的很精简有木有,可是可能会让人以为一会儿不太好消化。
const toArray = (function() { return Array.from ? Array.from : function(obj) { return Array.prototype.slice.call(obj); }; })();
这段代码和上段代码有殊途同归之妙,会不会好理解一些呢?若是以为仍是不太好理解,没事儿,咱再看一段代码。
const toArray = (function() { if (Array.from) { return Array.from; } else { return function(obj) { return Array.prototype.slice.call(obj); } } })();
看到这个简单明了了吧,若是仍是有什么疑问的话,那只能说,妈妈叫你回家学基础了。
Array.of()
与Array()
的异同
Array.of
的行为很统一。
Array.of() // [] Array.of(3) // [ 3 ] Array.of(3, 11, 8) // [ 3, 11, 8 ] Array.of(undefined) // [undefined]
当传入单个参数时,Array()
的行为表现的不统一。
Array() // [] Array(3) // [ , , ] Array(3, 11, 8) // [ 3, 11, 8 ]
童鞋们知道当传入单个参数时,Array是怎么处理的么?生成的数组的元素都是什么类型的呢?既然以前学了Array.from
相似map()
方法的运用,这里怎么的也得实战一会儿啊。
function typesof() { return Array.from(arguments, v => typeof v); } typesof(...Array(3)) // [ 'undefined', 'undefined', 'undefined' ]
这里还顺带了操做扩展符(...)逆转化数组的芝士点。不懂的童鞋看看阮一峰老湿的《函数的扩展》吧。请叫我雷锋。
Array.of方法能够用下面的代码模拟实现。
function ArrayOf() { return [].slice.call(arguments); }
数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其余位置(会覆盖原有成员),而后返回当前数组。也就是说,使用这个方法,会修改当前数组。
Array.prototype.copyWithin(target, start = 0, end = this.length)
它接受三个参数。
[1, 2, 3, 4, 5].copyWithin(0, 3) // [ 4, 5, 3, 4, 5 ]
上面代码表示将从3号位直到数组结束的成员(4和5),复制到从0号位开始的位置,结果覆盖了原来的1和2。
下面是更多例子。
// 将3号位复制到0号位 [1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [ 4, 2, 3, 4, 5 ] // 上面和下面这两个方法等同 // -2至关于3号位,-1至关于4号位 [1, 2, 3, 4, 5].copyWithin(0, -2, -1) // [ 4, 2, 3, 4, 5 ] // 将3号位复制到0号位 [].copyWithin.call({length: 5, 3: 1}, 0, 3) // { '0': 1, '3': 1, length: 5 } // 将2号位到数组结束,复制到0号位 var i32a = new Int32Array([1, 2, 3, 4, 5]); i32a.copyWithin(0, 2); // Int32Array [3, 4, 5, 4, 5]
对于没有部署TypedArray的copyWithin方法的平台,须要采用下面的写法。
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4); // Int32Array [4, 2, 3, 4, 5]
既然使用了copuWithin方法会修改当前数组,那么咱们就总结一下还有哪些方法也会更改当前数组,哪些则不会。只列取经常使用的,贵精不贵全。
不会修改当前数组的方法:
concat()
方法用于链接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被链接数组的一个副本。
var arr = Array.of(1, 2, 3); var resArr = arr.concat(4); arr // [ 1, 2, 3 ] resArr // [ 1, 2, 3, 4 ]
join()
方法用于把数组中的全部元素放入一个字符串。元素是经过指定的分隔符进行分隔的。
var arr = Array.of(1, 2, 3); var resStr = arr.join(","); arr // [ 1, 2, 3 ] resStr // 1,2,3
会修改当前数组的方法:
pop()
方法用于删除并返回数组的最后一个元素。
var arr = Array.of(1, 2, 3); var resEle = arr.pop(); arr // [ 1, 2 ] resEle // 3
push()
方法可向数组的末尾添加一个或多个元素,并返回新的长度。
var arr = Array.of(1, 2, 3); var resLen = arr.push('a'); arr // [ 1, 2, 3, 'a' ] resLen // 4
sort()
方法用于对数组的元素进行排序。
var arr = Array.of(3, 11, 8); var res = arr.sort(); arr // [ 11, 3, 8 ] res // [ 11, 3, 8 ]
结果是否是很意外,没错,排序并非按整型大小,而是字符串对比,就是取第一个字符的ANSI码对比,小的排前面,相同的话取第二个字符再比,若是要按整型数值比较,能够这样。
var arr = Array.of(3, 11, 8); var res = arr.sort((a, b) => a - b); arr // [ 3, 8, 11 ] res // [ 3, 8, 11 ]
reverse()
方法用于颠倒数组中元素的顺序。
var arr = Array.of(3, 11, 8, 9); var res = arr.reverse(); arr // [ 9, 8, 11, 3 ] res // [ 9, 8, 11, 3 ]
数组实例的find
方法,用于找出第一个符合条件的数组成员。
它的参数是一个回调函数,全部数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,而后返回该成员。若是没有符合条件的成员,则返回undefined。
[1, 4, -5, 10].find((n) => n < 0) // -5
上面代码找出数组中第一个小于0的成员。
[1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) // 10
上面代码中,find
方法的回调函数能够接受三个参数,依次为当前的值、当前的位置和原数组。
数组实例的findIndex
方法的用法与find
方法很是相似,返回第一个符合条件的数组成员的位置,若是全部成员都不符合条件,则返回-1。
fill 方法使用给定值,填充一个数组。
['a', 'b', 'c'].fill(7) // [7, 7, 7] new Array(3).fill(7) // [7, 7, 7]
上面代码代表,fill
方法用于空数组的初始化很是方便。数组中已有的元素,会被所有抹去。
fill
方法还能够接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
凡是带这种传参有startIndex和endIndex的方法,都是以startIndex开始,以endIndex为结束但不包含endIndex元素上的值。