LoginSignup
0
0

More than 5 years have passed since last update.

CreateJSのJavaScriptコードをECMAScript 6の構文に書き替える

Last updated at Posted at 2017-09-29

マウスポインタの位置に応じて立方体が回るつぎのサンプル001は、これまでのJavaScriptコードでCreateJSを用いて書きました。本稿では、これをECMAScript 2015(ECMAScript 6)の構文に書き替えてみます。併せて、CreateJSは最新のバージョン1.0.0を使いました。

サンプル001■EaselJS 0.8.2: Rotating a Cube around the X and Y axes

rotating_3d_cube.png
>> jsdo.itのサンプルコードへ

ECMAScript 6の新しい機能や構文については、たくさんの記事が解説しています。けれど、古い記述でも動くのですから、実際のコードでどこをどう書き改めたらよいのかピンとこない向きもあるでしょう。そこで、サンプルのコードをECMAScript 6に書き改めながら、そうすると何がどうよくなるのかご説明します。

変数の宣言

具体的なサンプルのコードに入る前に、変数の宣言について確かめておきましょう。ECMAScript 6では変数の宣言には、varだけでなくletconstが使えるようになりました。ともにブロックレベルのスコープをもちます。constは定数を定め、初期値は代入で書き替えられません(「JavaScript『再』入門」の「変数」参照)。

ECMAScript 6では新しいふたつの変数宣言を用い、値を変えない場合にはconstで定めると、変数の問題を避け、コードも確かめやすくなるでしょう。

クラスのコンストラクタとメソッド

これまでのJavaScriptコードでは、コンストラクタはfunctionキーワードで定め、メソッドをFunction.prototypeプロパティに加えました。つぎが、前掲サンプル001から抜書きしたコードです。

function Point3D(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
}
Point3D.prototype.getProjetedPoint = function(focalLength) {
    var point2D = new createjs.Point();
    var w = focalLength / (focalLength + this.z);
    point2D.x = this.x * w;
    point2D.y = this.y * w;
    return point2D;
};

ECMAScript 6はclass宣言を備えました。メソッドはそのブロックの中にfunctionキーワードなしで定めます。コンストラクタメソッドに用いる専用のキーワードがconstructor()です。

また、関数にはデフォルト引数が等価演算子=で与えられます。引数が渡されないときに用いられる値です。

class Point3D {
    constructor(x = 0, y = 0, z = 0) {
        this.x = x;
        this.y = y;
        this.z = z;     
    }
    getProjetedPoint(focalLength) {
        let point2D = new createjs.Point();
        let w = focalLength / (focalLength + this.z);
        point2D.x = this.x * w;
        point2D.y = this.y * w;
        return point2D;
    }
}

クラスの継承

ECMAScript 5の継承は、Object.prototypeプロパティObject.create()メソッドで親コンストラクタのプロトタイプからつくったオブジェクトを代入して行いました。そして、サブクラスのコンストラクタからスーパークラスのコンストラクタを呼ぶのに使われたのがFunction.call()メソッドです。

function Shape() {
  this.x = 0;
  this.y = 0;
}
Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
};
function Rectangle() {
    Shape.call(this);
}
Rectangle.prototype = Object.create(Shape.prototype);

ECMAScript 6では、継承にはextendsキーワード、親コンストラクタの呼び出しはsuperキーワードが使えます。つぎに抜書きしたサンプル001のコンストラクタFaceには、とくに継承を定めていません。配列のようにプロパティを扱いたかったのに、組み込み済みのArrayクラスが継承できなかったためです。

function Face(pos0, pos1, pos2, pos3, color) {
    this.length = 4;
    this.color = color;
    this[0] = pos0;
    this[1] = pos1;
    this[2] = pos2;
    this[3] = pos3;
}

ECMAScript 6のclass宣言を使えば、つぎのようにArrayクラスも原則の構文にしたがって継承できるのです。

class Face extends Array {
    constructor(pos0, pos1, pos2, pos3, color) {
        super(pos0, pos1, pos2, pos3);
        this.color = color;
    }
}

静的メソッドと分割代入

これまでのJavaScriptでは、静的なメソッドはコンストラクタ関数に直に定めました。サンプル001から抜書きしたつぎのクラスMathUtilsは、コンストラクタが要らないのでオブジェクトにしました。静的メソッドMathUtils.getRandomIntは、引数ふたつの大小を比べて、順序を整えています。

var MathUtils = {};
MathUtils.getRandomInt = function(min, max) {
    if (min > max) {
        var temp = min;
        min = max;
        max = temp;
    }
    var randomNumber = Math.random() * (max - min) + min;
    return Math.floor(randomNumber);
};

ECMAScript 6には、staticキーワードが加わりました。classの本体のメソッドにstaticを添えれば静的な扱いになります。また、複数の変数に値が同時に代入できる分割代入の構文も採り入れられました。変数の値の入れ替えが簡単にできます。

class MathUtils {
    static getRandomInt(min, max) {
        if (min > max) {
            [min, max] = [max, min];
        }
        const randomNumber = Math.random() * (max - min) + min;
        return Math.floor(randomNumber);
    }
}

なお、静的プロパティの定めはまだ備わっていません。これまでと同じく、クラスに直に加えることになります。ECMAScript 5.1のObject.defineProperty(https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)メソッドを使ってもよいでしょう。

Point3D._point = new createjs.Point();
// または
Object.defineProperty(Point3D, '_point', {
    value: new createjs.Point()
});

アロー関数式とArrayクラスのメソッド

ECMAScript 5.1で、Arrayクラスにはfor文は使わず配列要素すべてを扱えるメソッドがいくつか備わりました。引数には関数を渡します。このとき、ECMAScript 6のアロー関数式=>を用いると、さらにすっきりとコードが書けます。名前のない関数(無名関数)でfunctionキーワードは省き、代わりにアロー=>を使う構文です。

つぎに抜書きしたのは、サンプル001でfor文により配列の3次元座標を処理している関数rotate()です。

function rotate(eventObject) {
    var count = points.length;
    var RAD_TO_DEG = 1 / createjs.Matrix2D.DEG_TO_RAD;
    points2D.length = 0;
    matrixY.identity().rotate(angle.y * RAD_TO_DEG);
    matrixX.identity().rotate(angle.x * RAD_TO_DEG);
    for (var i = 0; i < count; i++) {
        var point = points[i];
        point.rotatePoint(matrixY, 'y');
        point.rotatePoint(matrixX, 'x');
        points2D[i] = point.getProjetedPoint(focalLength);
    }
    drawFaces(points2D, facesVertices);
}

Array.map()メソッドは、配列要素を順に取り出して処理したうえで、戻り値の要素からなる新たな配列を返します。引数に渡すのは、その処理と戻り値を定めた関数です。関数rotate()は、つぎのように書き替えられます。for文のようなカウンタ変数が要りません。

function rotate(eventObject) {
    const RAD_TO_DEG = 1 / createjs.Matrix2D.DEG_TO_RAD;
    matrixY.identity().rotate(angle.y * RAD_TO_DEG);
    matrixX.identity().rotate(angle.x * RAD_TO_DEG);
    points2D = points.map((point) => {
        point.rotatePoint(matrixY, 'y');
        point.rotatePoint(matrixX, 'x');
        return point.getProjetedPoint(focalLength);
    });
    drawFaces(points2D, facesVertices);
}

もうひとつサンプル001から、クラスFaceのメソッドgetFacePoints()をご紹介します。インスタンスにインデックスで定めたプロパティを順に取り出して、新たな配列にして返しています。

Face.prototype.getFacePoints = function (points) {
    var faces = this.length;
    var facePoints = [];
    for (var i = 0; i < faces; i++) {
        facePoints[i] = points[this[i]];
    }
    return facePoints;
};

ECMAScript 6では、組み込み済みのArrayクラスが継承できました。すると、クラスFaceのメソッドとしてArray.map()が呼び出せます。アロー関数式で本体が1行のステートメントのときは、ブロックの波かっこ{}が省けます。そして、式の値が自動的に返されるので、returnも要りません。

class Face extends Array {

    getFacePoints(points) {
        const facePoints = this.map((element) => points[element]);
        return facePoints;
    }
}

Arrayクラスの新しいメソッドの使い方については「JavaScriptのArrayクラスのメソッドで要素の標準偏差を求める」をご参照ください。

これらの手直しを加えたコードが、つぎのサンプル002です。

サンプル002■EaselJS 1.0.0 + ES6: Rotating a Cube around the X and Y axes

rotating_3d_cube.png
>> jsdo.itのサンプルコードへ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0