ECMAScript 2015 – 陣列新特性

by vivid 8. 二月 2017 10:42

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N170218001
出刊日期: 2017/02/08

本文將介紹ECMAScript 2015的為陣列提供的新功能,以及操作陣列的新語法,例如of()、from()、find()、fill()…方法。

陣列(Array)

在ECMAScript 5,陣列的建構函式行為有點詭異。參考以下範例程式碼,使用Array建構函式建立一個陣列,在建構函式傳入數值「10」,表示要建立一個可以存放「10」個項目的陣列,因此length屬性的值會是「10」:

var ar = new Array( 10 );
console.log( ar.length ); // 10

若Array的建構函式傳入字串型別參數,行為就不同了,參考以下範例程式碼,在建構函式傳入字串「"10"」,那麼實際上只會在陣列中建立一個項目,length屬性的值會是「1」,而利用索引取出此項目的內容為「10」:

var ar = new Array( "10" );
console.log( ar.length ); // 1
console.log( ar[0] ); // 10

若Array的建構函式傳遞兩個以上的參數,行為也不同。參考以下範例程式碼,建立一個陣列,在建構函式傳入「10」與「20」兩個參數,但實際上,會建立一個陣列,可以存放「2」個項目,因此length屬性的值會是「2」,利用索引可以取出這兩個項目的內容,分別是「10」與「20」:

var ar = new Array( 10, 20 );
console.log( ar.length ); // 2
console.log( ar[0] ); // 10
console.log( ar[1] ); // 20

這麼奇怪的邏輯真是令人費解。ECMAScript 2015為陣列新增了一些方法來建立陣列,如此可以避免使用Array建構函式來建立陣列物件,以及陣列中的項目,這樣你就不需要去記憶上述的因參數個數、型別不同的陣列建立邏輯。

Array.of()方法

ECMAScript 2015新增了Array.of() 方法,來建立並初始化陣列中的項目,Array.of() 方法會將傳入的參數新增到陣列之中,參考以下範例程式碼,叫用Array.of() 方法建立一個陣列,傳入參數數值「10」,表示要建立可以存放「1」個項目的陣列,因此length屬性的值會是「1」,利用索引可以取出這個項目的內容為「10」:

var ar = Array.of( 10 );
console.log( ar.length ); // 1
console.log( ar[0] ); // 10

若Array.of()方法傳入一個字串當參數,同樣會建立一個可以存放1個項目的陣列,length屬性的值會是「1」,利用索引可以取出這個項目的內容為「10」:

var ar = Array.of( "10" );
console.log( ar.length ); // 1
console.log( ar[0] ); // 10

參考以下範例程式碼,使用Array.of()方法建立一個陣列,可以存放「2」個項目,因此length屬性的值會是「2」,利用索引可以取出這兩個項目的內容分別為「10」、「20」:

var ar = Array.of( 10, 20 );

console.log( ar.length ); //2

console.log( ar[0] ); //10

console.log( ar[1] ); //20

 

Array.from()方法

在ECMAScript 5,要將類似Array的物件轉換成陣列,可以使用Array.prototype.slice()方法,參考以下範例程式碼,在getArray()方法中,使用Array.prototype.slice()方法,將類似陣列的arguments物件內容取出,放到一個新陣列再回傳:

function getArray() {
  return Array.prototype.slice.call( arguments );
}

var result = getArray( 1, 2, 3 );
for( n of result )
{
  console.log( n ); // 1 , 2 , 3
}


 

 

ECMAScript 2015的Array.from()方法可以將一個非陣列的物件,轉換成陣列(Array),也可以用來複製一個陣列,然後將新建立的陣列回傳。參考以下範例程式碼,在getArray()方法中,將類似陣列的arguments物件內容取出,放到一個新陣列再回傳:

function getArray() {
  return Array.from( arguments );
}

var result = getArray( 1, 2, 3 );
for( n of result )
{
  console.log( n ); // 1 , 2 , 3
}

 

參考以下範例程式碼,則是使用Array.from()方法將Set物件中的項目轉成陣列:

var source = new Set( [10, 20, 30] );

var ar = Array.from( source );

console.log( ar.length ); // 3

console.log( ar[0] ); // 10

console.log( ar[1] ); // 20

console.log( ar[2] ); // 30

參考以下範例程式碼,複製source陣列中的項目到新的ar陣列,並將新陣列回傳,因此複製動作完成之後,若修改source陣列中的第0個項目的值,並不會影響新ar陣列的第0個項目:

var source = [10, 20, 30];

var ar = Array.from( source );

console.log( ar.length ); //3

console.log( ar[0] ); // 10

console.log( ar[1] ); // 20

console.log( ar[2] ); // 30

source[0] = 40;

console.log( source[0] ); // 40

console.log( ar[0] ); // 10

若轉換成新陣列需要一些複雜的計算邏輯,則可以在叫用Array.from()方法時,傳入第二個參數,通常是一個箭頭函式(Arrow Function),在其中撰寫轉換邏輯,參考以下範例程式碼,將陣列項目做平方計算,回傳乘積後,將乘積放到新陣列 :

var source = [ 10, 20, 30 ];

var ar = Array.from( source, ( i ) => i * i );

console.log( ar.length ); // 3

console.log( ar[0] ); // 100

console.log( ar[1] ); // 400

console.log( ar[2] ); // 900

你也可以將轉換邏輯寫在物件的方法上,然後將此方法名稱傳遞到Array.from()方法第二個參數,參考以下範例程式碼,轉換的程式定義在calc物件的doubleNumber()方法之中,doubleNumber方法將陣列項目做平方計算,回傳乘積後,將乘積放到新陣列:

let calc = {
  doubleNumber( i ) { return i * i; }
};

var source = [ 10, 20, 30 ];
var ar = Array.from( source, calc.doubleNumber );
console.log( ar.length ); // 3
console.log( ar[0] ); // 100
console.log( ar[1] ); // 400
console.log( ar[2] ); // 900

 

若轉換邏輯寫在一個物件上,而你將方法名稱傳遞到Array.from()第二個參數,那麼你還可以利用第三個參數來指定this,這樣就可以存取包含轉換函式的物件之屬性,參考以下範例程式碼:

let calc = {
  num : 5,
  doubleNumber(i) { return i * this.num; }
};

var source = [ 10, 20, 30 ];
var ar = Array.from( source, calc.doubleNumber, calc );
console.log( ar.length); // 3
console.log( ar[0] ); // 50
console.log( ar[1] ); // 100
console.log( ar[2] ); // 150

 

find()方法

ECMAScript 5版之前,沒有內建的方法可以用於搜尋陣列,只有index()與indexOf()方法,用於搜尋項目所在的索引。在ECMAScript 2015新增多種方法來操作與搜尋其中的資料,以下分別介紹這些方法。

find()方法可以找尋陣列中第一個滿足條件的資料,一次只能找尋一個值,若要找兩個以上的值就要自己想辦法。find()方法傳入的第一個參數是一個回呼函式(callback),用來設定篩選條件。

參考以下範例程式碼,使用find()方法從ar陣列找尋陣列中第一個大於、等於「15」的數值,然後印出它的值:

var ar = [ 10, 5, 25, 75, 56, 96 ];
var r = ar.find( function ( n ) {
  return n >= 15;
});
console.log( r ); // 25

 

回呼函式(callback)可以改用箭頭函式(Arrow Function)來取代,參考以下範例程式碼,可以得到和上例相同的執行結果:

var ar = [ 10, 5, 25, 75, 56, 96 ];

var r = ar.find( n => n >= 15 );

console.log( r ); // 25

 

thisArgs參數

find ()方法可以傳入兩個參數,第一個參數是一個回呼函式(callback),用來設定篩選條件;第二個參數是個選擇性的參數,在函式中可以使用this來存取它的值,參考以下範例程式碼,將x物件傳入find()方法第二個參數,在回呼函式(callback)中就可以取得x物件的nums屬性:

var x = {
  nums : 15
};

var ar = [ 10, 5, 25, 75, 56, 96 ];
var r = ar.find( function ( n ) {
  console.log( this.nums ); //15
  return n >= this.nums;
}, x);
console.log( r ); //25

 

findIndex()方法

findIndex()方法可以找尋陣列中第一個滿足條件的資料之索引值,一次只能找尋一個值,findIndex()方法的第一個參數是一個回呼函式(callback),參考以下範例程式碼,找尋第一個大於、等於「15」的數值,然後回傳「25」位於ar中的索引「2」:

var ar = [ 10, 5, 25, 75, 56, 96 ];
var r = ar.findIndex( function ( n ) {
  return n >= 15;
});

console.log( r ); //2

回呼函式(callback)可以改用箭頭函式(Arrow Function),改寫上述範例程式碼如下:

var ar = [10, 5, 25, 75, 56, 96];

var r = ar.findIndex(n => n >= 15);

console.log(r); //2

findIndex()方法和find ()方法一樣,可以傳入兩個參數,第一個參數是一個回呼函式(callback),用來設定篩選條件;第二個參數是個選擇性的參數,在函式中可以使用this來存取它的值,參考以下範例程式碼,將x物件傳入findIndex()第二個參數,並用「this.nums」語法取得x物件的nums屬性值:

var x = {
  nums : 15
};

var ar = [ 10, 5, 25, 75, 56, 96 ];
var r = ar.findIndex( function ( n ) {
  console.log( this.nums ); //15
  return n >= this.nums;
}, x );
console.log( r ); //2

 

找尋NaN

findIndex()方法可以用來找尋NaN,例如以下範例程式中,ary陣列中包含一個NaN,使用findIndex()方法,可以得知NaN出現在索引「2」的位置,若使用indexOf()方法,會得到「-1」,無法判斷NaN所在位置:

const ary = [ '100', 200, NaN ];

console.log( ary.findIndex( x => Number.isNaN(x)) ); // 2

console.log( ary.indexOf( NaN )); // –1

 

fill()方法

在ECMAScript 5要將陣列中包含的項目值全部填成「undefined」,可以使用Array.apply()方法,參考以下範例程式碼,利用new關鍵字建立一個含五個項目的陣列,其中的項目預設都是「undefined」:

var ar = Array.apply( null, new Array(5) );

console.log(ar); // [undefined, undefined, undefined, undefined, undefined]

而ECMAScript 2015則使用fill()方法,來達到相同的效果,參考以下範例程式碼:

var ar = new Array(5).fill(undefined);

console.log(ar); // [undefined, undefined, undefined, undefined, undefined]

在ECMAScript 5若要將陣列的一到多個項目設定為指定的值,可以利用map方法,以下範例程式碼,先利用new關鍵字建立一個含五個項目的陣列,再叫用map方法回傳一個新陣列,將陣列中所項目的值都填為「100」:

var ar = Array.apply( null, new Array(5) ).map( function ( x ) { return 100 } );

console.log( ar ); // [ 100, 100, 100, 100, 100 ]

ECMAScript 2015的fill()方法,可以用來將陣列的一到多個項目設定為指定的值,以下範例程式碼,同樣將陣列中所項目的值都填為「100」 :

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.fill( 100 );

console.log( ar ); // [ 100, 100, 100, 100, 100, 100 ]

若不是所有項目都要填入相同的值,可以使用fill()方法第二個參數,指定要從哪一個索引位置開始填值,參考以下範例程式碼,從索引位置一開始將剩餘項目的值填為「100」:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.fill( 100, 1 );

console.log( ar ); // [ 10, 100, 100, 100, 100, 100 ]

參考以下範例程式碼,從索引位置二開始將剩餘項目的值填為「100」:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.fill( 100, 2 );

console.log( ar ); // [ 10, 5, 100, 100, 100, 100 ]

fill()方法第三個參數可以指定要填值的結尾索引(不包含結尾索引項目),參考以下範例程式碼,從索引位置一開始將值填為「100」 ,結束在索引「3」,但不包含索引「3」的項目:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.fill( 100, 1, 3 );

console.log( ar ); // [ 10, 100, 100, 75, 56, 96 ]

若fill()方法第二個參數傳入的數值是負數,那麼便從「array.length-負數值」索引位置開始填值,參考以下範例程式碼,傳入「-1」,便從索引5位置開始填100:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.fill( 100, -1 );

console.log( ar ); // [ 10, 5, 25, 75, 56, 100 ]

第二個參數若傳入「-2」數,便從索引4 位置開始填100:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.fill( 100, -2 );

console.log( ar ); // [ 10, 5, 25, 75, 100, 100 ]

copyWithin()方法

copyWithin()方法可以讓你複製陣列本身的項目,項目可以有多個,此方法需要傳入兩個參數,一為要開始填值的索引;二為要開始複製值的索引。

參考以下範例程式碼,從索引3開始填值,複製索引0的值填入:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.copyWithin( 3, 0 );

console.log( ar ); // [ 10, 5, 25, 10, 5, 25 ]

以下範例程式碼,從索引3開始填值,貼上從索引1複製的值:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.copyWithin( 3, 1 );

console.log( ar ); // [ 10, 5, 25, 5, 25, 75 ]

copyWithin()方法可以傳入第三個參數,指定要停止複製的索引,例如以下範例程式碼,從索引3開始,貼上從索引值1複製的值,但遇到索引3則停止複製:

var ar = [ 10, 5, 25, 75, 56, 96 ];

ar.copyWithin( 3, 1, 3 );

console.log(ar); // [ 10, 5, 25, 5, 25, 96 ]

Typed Arrays

JavaScript數值使用64位元來儲存數值,此格式可以儲存浮點數或整數。Typed Arrays是特殊用途的陣列,搭配數值型別使用,不適用所有型別,針對位元數學運算最佳化。Typed Arrays一開始是為了進行繪圖的需要而設計出來的。

Typed Arrays可以儲存以下數值型別:

  • 帶正負號的 8 位元整數(int8)
  • 不帶帶正負號的 8 位元整數(uint8)
  • 帶正負號的 16 位元整數(int16)
  • 不帶帶正負號的 16 位元整數(uint16)
  • 帶正負號的 32 位元整數(int32)
  • 不帶帶正負號的 32 位元整數(uint32)
  • 32 位元符點數(float32)
  • 62 位元符點數(float64)

參考以下範例程式碼,為使用Typed Array範例:

var int32 = new Int32Array(2);

int32[0] = 100;

int32[1] = 200;

console.log(int32[0]); // 100

console.log(int32[1]); // 200

Tags:

.NET Magazine國際中文電子雜誌 | JavaScript | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List