es 6配列の拡張演算子の動作例の分析


この例は、es 6配列の拡張演算子動作を説明する。皆さんに参考にしてあげます。具体的には以下の通りです。
拡張演算子は3つの点です。これは、restパラメータの逆演算のように、1つの配列をコンマで区切られたパラメータ系列に変換します。

console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]

演算子は主に関数呼び出しに使用されます。

function push(array, ...items) {
 array.push(...items)
}
function add(x, y) {
 return x + y
}

const numbers = [4, 38]
add(...numbers) // 42

上のコードでは、array.push(...items)とadd(...numbers)の2つの行は、関数の呼び出しであり、それらは拡張演算子を使用しています。演算子は、行列をパラメータ系列に変えます。
拡張演算子は、通常の関数パラメータと組み合わせて使用できます。非常に柔軟です。

function f(v, w, x, y, z) {}
const args = [0, 1]
f(-1, ...args, 2, ...[3])

拡張演算子の後に式を置くこともできます。

const arr = [
 ...(x > 0 ? ['a'] : []),
 'b'
]

拡張演算子の後に空の配列がある場合、効果はありません。

[...[], 1]

ただし、拡張演算子を括弧に入れると、javaScriptエンジンは関数呼び出しとみなされます。この場合は関数で呼ばないとエラーが発生します。

(...[1, 2])
// Uncaught SyntaxError: Unexpected number

console.log((...[1, 2]))
// Uncaught SyntaxError: Unexpected number

console.log(...[1, 2])
// 1 2

上の二つの場合はエラーが発生します。拡張演算子の括弧は関数呼び出しではなく、第三の場合はconsone.log(…[1,2])はエラーが発生しないため、関数呼び出しです。
次は、拡張演算子がapplyメソッドに代わる実際の例であり、Math.max方法を適用して、1つの配列の最大要素の書き方を簡略化して求める。

// ES5   
Math.max.apply(null, [14, 3, 77])

// ES6   
Math.max(...[14, 3, 77])

//    
Math.max(14, 3, 77)

上のコードの中で、javaScriptは配列の最大要素を求める関数を提供しないので、Math.max関数を当てはめて、配列を一つのパラメータシーケンスに変えて、最大値を求めます。拡張演算子があれば、そのままMath.maxを使うことができます。
もう一つの例は、push関数により、もう一つの配列の末尾に一つの配列を追加することである。

// ES5    
var arr1 = [0, 1, 2]
var arr2 = [3, 4, 5]
Array.prototype.push.apply(arr1, arr2)
// ES6   
let arr1 = [0, 1, 2]
let arr2 = [3, 4, 5]
arr1.push(...arr2)

上のコードのES 5の書き方では、pushメソッドのパラメータは配列ではないので、pushメソッドをappyメソッドで変換して使用します。拡張演算子があれば、直接に行列をプッシュすることができます。
次は別の例です。

// ES5
new (Date.bind.appy(Date, [null, 2015, 1, 1]))
// ES6
new Date(...[2015, 1, 1])

拡張演算子の適用
1)行列のコピー
配列は複合データタイプで、直接コピーすると、新しい配列をクローンするのではなく、下のデータ構造を指すポインタをコピーするだけです。

const a1 = [1, 2]
const a2 = a1 
a2[0] = 2
a1 // [2, 2]

上のコードでは、a 2はa 1のクローンではなく、同じデータの別のポインタを指しています。a 2を修正すると、a 1の変化が直接的に引き起こされます。
ES 5は、行列をインチング方法でコピーすることしかできません。

const a1 = [1, 2]
const a2 = a1.concat()

a2[0] = 2 
a1 //[1, 2]

ES 6書き方

const a1 = [1, 2]
//   1
const a2 = [...a1]
//   2
const [...a2] = a1

2)連結配列
拡張演算子は、行列結合の新しい書き方を提供します。

const arr1 = ['a', 'b']
const arr2 = ['c']
const arr3 = ['d', 'e']
// ES5     
arr1.concat(arr2, arr3)
// ES6     
[...arr1, ...arr2, ...arr3]

でも、この二つの方法は全部薄いコピーで、使う時は注意が必要です。

const a1 = [{foo: 1}]
const a2 = [{bar: 2}]
const a3 = a1.concat(a2)
const a4 = [...a1, ...a2]

a3[0] === a1[0] // true
a4[0] === a1[0] // true

上のコードでは、a 3とa 4は2つの異なる方法で結合された新しい配列であるが、それらのメンバーは元の配列のメンバへの参照であり、これは浅いコピーであり、元の配列のメンバを修正すれば、新しい配列に同期して反映される。
3)分配値と結合する
拡張演算子は、行列を生成するために、構文化された値と組み合わせることができます。

// ES5 
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list

次は別の例です。

const [first, ...rest] = [1, 2, 3, 4, 5]
first // 1
rest // [2, 3, 4, 5]

const [first, ...rest] = []
first // undefined
rest // []

行列の割り当てに拡張演算子を使うと、パラメータの最後のビットにしか入れられません。そうでないとエラーが発生します。

const [...butLast, last] = [1, 2, 3, 4, 5];
//   

const [first, ...middle, last] = [1, 2, 3, 4, 5];
//   

(4)文字列
拡張演算子は、文字列を真の行列に変換することもできます。

[...'hello']
// [ "h", "e", "l", "l", "o" ]

Iteratorインターフェースが配置されていない類似の配列のオブジェクトに対しては、拡張演算子は、それを真の配列に変換することができません。

let arrayLike = {
 '0': 'a',
 '1': 'b',
 length:2
}

// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];

上のコードでは、arrayLikeは配列のようなオブジェクトですが、Iteratorインターフェースが配備されていないため、拡張演算子がエラーとなります。このとき、arrayLikeをarray.from法を用いて本物の配列に変えることができる。
拡張演算子の内部呼び出しは、データ構造のIteratorインターフェースであるので、Iteratorインターフェースを有するオブジェクトであれば、拡張演算子、例えばMap構造を使用することができる。

let map = new Map([
 [1, 'one'],
 [2, 'two'],
 [3, 'three'],
]);

let arr = [...map.keys()]; // [1, 2, 3]

興味のある友達はオンラインHTML/CSS/JavaScriptコードを使ってツールを実行できます。http://tools.jb51.net/code/HtmlJsRun上記コードの運行効果をテストします。
もっと多くのJavaScriptに関する内容は当駅のテーマを調べられます。「JavaScript常用関数技術のまとめ」、「javascript対象向け入門教程」、「JavaScriptエラーとデバッグテクニックのまとめ」、「JavaScriptデータ構造とアルゴリズム技術のまとめ」及び「JavaScript数学演算の使い方のまとめ
本論文で述べたように、JavaScriptプログラムの設計に役に立ちます。