ES6 新特性之數組擴展

Array.from()

from 方法用於將兩類對象轉爲真正的數組:相似數組的對象(array-like object)和可遍歷(iterable)的對象(包括ES6新增的數據結構Set和Map)。javascript

語法

Array.from(arrayLike[, mapFn[, thisArg]])

參數

  • arrayLike

    想要轉換成數組的僞數組對象或可迭代對象。java

  • mapFn (可選參數)

    若是指定了該參數,新數組中的每一個元素會執行該回調函數。es6

  • thisArg (可選參數)

    可選參數,執行回調函數 mapFnthis 對象。數組

返回值

一個新的數組實例瀏覽器

常規用法

將字符串轉化爲數組。數據結構

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.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);
}

Array.ptototype.copyWithin()

常規用法

數組實例的copyWithin方法,在當前數組內部,將指定位置的成員複製到其餘位置(會覆蓋原有成員),而後返回當前數組。也就是說,使用這個方法,會修改當前數組。

Array.prototype.copyWithin(target, start = 0, end = this.length)

它接受三個參數。

  • target(必需):從該位置開始替換數據。
  • start(可選):從該位置開始讀取數據,默認爲0。若是爲負值,表示倒數。
  • end(可選):到該位置前中止讀取數據,默認等於數組長度。若是爲負值,表示倒數。
    這三個參數都應該是數值,若是不是,會自動轉爲數值。
[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 ]

Array.prototype.find()

數組實例的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方法的回調函數能夠接受三個參數,依次爲當前的值、當前的位置和原數組。

Array.prototype.findIndex()

數組實例的findIndex方法的用法與find方法很是相似,返回第一個符合條件的數組成員的位置,若是全部成員都不符合條件,則返回-1。

Array.prototype.fill()

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元素上的值。

相關文章
相關標籤/搜索