1. FumioNonaka

    No comment

    FumioNonaka
Changes in body
Source | HTML | Preview

新しいArrayクラスのメソッドを用いると、forループは使わずに配列要素が処理できます。ただ、もとになる配列がないとき、必要な要素が納められた配列をどのようにつくればよいか考えなければなりません。

forループでCanvasに描画するサンプルコード

お題にするforループを使った関数がつぎのコード001です(「スタイルと色を適用する」参照)。色相が変化した小さい正方形を、Canvasにタイル状に並べます。引数は小さい正方形の一辺の長さと、縦横に並べる個数です。draw(25, 4)で呼び出すと、Canvasには以下の図001の図形が描かれます。jsdo.itに「Drawing squares on Canvas with for loop」として掲げました。

コード001■forループを使ってCanvasに描画する

function draw(side, count) {
    var context2d = document.getElementById('myCanvas').getContext('2d');
    var amount = count * count;
    var angle = 360 / (amount - 1);
    for (var i = 0; i < count; i++) {
        for (var j = 0; j < count; j++) {
            context2d.fillStyle = 'hsl(' + angle * (i * count + j) + ', 100%, 50%)';
            context2d.fillRect(j * side, i * side, side, side);
            console.log(angle * (i * count + j));
        }
    }
}

図001■色相の変化した正方形がタイル状に並ぶ

1710002_001.png

思いつくのは、Array()コンストラクタで長さを決めてつくった配列に、要素はArray.map()メソッドで加えるやり方です。ところが、返されるのは空の配列です。Array.map()メソッドは、値が(undefinedにしても)代入されていない要素については、コールバックを呼び出さないからです。

new Array(amount).map(() => 0)  // []

Array.fill()メソッドで配列要素を埋める

ECMAScript 6に備わったArray.fill()メソッドメソッドは、引数の値を指定したインデックに代入します。これで、長さを定めた配列の要素は埋められますから、Array.map()メソッドが呼び出せます。

前掲コード001のfor文を使った処理は、つぎのコード002のようにArrayクラスのメソッドで替えられるのです。jsdo.itにも「ES6: Drawing squares on Canvas with Array methods」を掲げました。

コード002■for文は使わずにArrayクラスのメソッドで処理する

function draw(side, count) {
    const context2d = document.getElementById('myCanvas').getContext('2d');
    const amount = count * count;
    const angle = 360 / (amount - 1);
    new Array(amount).fill(0, 0).map((data, i) => ({
        color: `hsl(${angle * i}, 100%, 50%)`,
        x: i % count * side,
        y: Math.floor(i / count) * side
    }))
    .forEach((data) => {
        context2d.fillStyle = data.color;
        context2d.fillRect(data.x, data.y, side, side);
    });
}

Array.from()メソッドで新たな要素の配列をつくる

ECMAScript 2015のArrayクラスには、Array.from()メソッドも加わりました。配列型(array-like)あるいは反復可能(iterable)オブジェクトから、新たにArrayインスタンスをつくるのがもともとの役割です。けれどさらに、第2引数にマップのためのコールバック関数が与えられます。そして、第1引数が長さを決めただけの要素のない配列でも、コールバック関数が呼び出せるのです。

前掲コード002は、Array.from()メソッドを使ってつぎのように書き替えることもできます。

// new Array(amount).fill(0, 0).map((data, i) => ({
Array.from(new Array(amount), (data, i) => ({
    // プロパティ
}))

スプレッド演算子で配列要素を分ける

ECMAScript 2015にスプレッド演算子...が備わりました。配列要素を分けて親配列の要素にできるのです。この演算子を使って、前掲コード002はつぎのように書き替えることもできます。

[...new Array(amount)].map((data, i) => ({
    // プロパティ
}))

[2018年1月23日: 本項を追記]