22.2.2 【プログラミングの罠】ES6とBabelとIE

Javascript言語は、もともとは各Webブラウザでの違いが大きかったのですが、現在では標準化が進んでいます。標準化された名称がECMAScriptです。その第6版が通称としてES6と呼ばれ、規格としての正式名称はECMAScript2015です。その後のさらに新しい規格としてECMAScript2017があります。これらの最近の規格では、Javascript言語の弱点を補う改良が施されているので、ぜひ活用したいものです。ここでは主な機能だけ紹介しますが、ECMAScript2015やECMAScript2017と検索していただくと解説しているサイトがいろいろ見つかると思います。

Buddyアプリのスクリーンスクリプトはブラウザ上で実行されるので、使える機能はそのブラウザのJavascript言語の実装に依存することになります。Edge、Chrome、Firefoxといったブラウザはみな最近のJavascriptの規格に対応していますが、IE(Internet Explorer)は基本的に対応していません。

しかし、IEでもES6の新しい機能を使えるようにするBabelという仕組みがあります。これはES6の文法で書かれたスクリプトを古いES5で実行できるスクリプトに変換してくれるものです。Buddyではアプリ生成の際のオプションでBabelを使用するように指定することができます。ただし、変換されたスクリプトが実行されることになるのでデバッグの際にブラウザでソースコードを見ると元のスクリプトとは異なることになって、わかりにくくなるという難点はあります。

ES6になれた方だとBuddyアプリの開発でも下記でご紹介するようなES6の機能を使ったスクリプトを自然に書いてしまう場合もあるでしょう。それをBabelを使用しないでアプリとして生成すると、Edge、Chrome、Firefoxでは問題ないが、IEでは動かないということになりますので注意が必要です。アプリ開発の一般的な注意事項ですが、そのアプリはどのブラウザで利用するのかをあらかじめきちんと決めておくこと、そして対象のブラウザでテストすることが重要です。IEを対象外とできる場合は、ES6をどんどん使うことができ、Babelを使用する必要もなくなります。

以上が今回の「プログラミングの罠」ですが、ES6の新しい機能が具体的にわからないとピンとこないかもしれません。Buddyのアプリ開発でもすぐに役立ちそうな点に絞っていくつかご紹介します。

letとconst

変数の定義は従来はvarで行いますが、varには、何度も同じ変数を定義できる、スクリプト全体から見える、という大きな弱点があります。

var a = 1;
if(true) {
	var a = 2;
}
console.log(a);

この場合、最初の var a と、ifの中の var a は同じ変数になり、最後のconsole.logは 2 と表示されることになります。変数の定義は、本来は一度だけ適切な場所で行われるべきもので、そうでない状況はバグの原因になります。しかしコピーアンドペーストで編集したりすると同じ名前の変数を二箇所以上で定義している状況が生まれることがあり、var ではこれがエラーにならないため、気づきにくいのです。

letはvarと同様に変数を定義しますが、指定の変数名が既存だとエラーになります。また、{ } の間であればその中に有効範囲が限定されます。

let a = 1;
if(true) {
	let a = 2;
}
console.log(a);

このように先ほどの var を let に返ると、このスクリプトはifの中の let a のところで「a はすでにあるよ」という意味のエラー二なります。

let a = 1;
if(true) {
	let b = 2;
}
a = b;
console.log(a);

こうすればletでのエラーは起こりませんが、a = b; のところで「bは未定義」という意味のエラーになります。let b はifの{ }の中にあるため、その中だけで有効な変数となり、外側で使おうとするとこうなるわけです。
var だとあるところで定義して使った変数が、無関係なところでも見えてしまってバグの原因になることがありますが、let ではそれが防げます。

const は let と同様ですが、定義した変数の値を変更することができないという違いがあります。

const c = 1;
c = 2;

これは c = 2; のところでエラーになります。変更されるべきでないものは const にしておくと安心です。

アロー関数

Javascriptでは無名関数をよく使います。代表的なものが非同期処理でのコールバックです。例えばBuddyではDBテーブルからデータを読み出すreadDataは次のようになります。

this.tables.table1.readData(options, function(err, data){
	…
});

この function(err, data){ … } が無名関数です(通常の関数定義であれば function の後の括弧の前にある関数名がありません)。readDataの処理が終わるとこの無名関数が呼ばれ、引数のerrやdataで結果を得ることができます。
これをES6のアロー関数で書くと次のようになります。function を省略して ) と { の間に => を書きます。

this.tables.table1.readData(options, (err, data) => {
	…
});

これだけだと、書き方が簡便になったくらいのことですが、従来の無名関数とはthisの扱いが異なります。従来の無名関数ではthisは関数を呼び出したオブジェクトですが、アロー関数では定義時のthisになります。
例えば上記の例で、得られたレコード数をLABEL1にセットして表示したい場合、従来の無名関数では、

this.tables.table1.readData(options, (function(err, data){
	this.items.LABEL1.setValue(data.length);
}).bind(this));

のように、bind(this) を付ける必要があります。しかしアロー関数では、

this.tables.table1.readData(options, (err, data) => {
	this.items.LABEL1.setValue(data.length);
});

と、bind(this)無しでOKで、非常にすっきりします。

テンプレート文字列

Javascriptでは文字列はシングルクォート「’」またはダブルクォート「”」で囲みます。ES6ではこれに加えてバッククォート「`」で囲むことができ、その場合は ${変数名} で変数の値を埋め込むことができます。また途中に改行を入れることもできます。

従来であれば、

const name = '名前';
const age = 25;
const s = "名前: " + name + "\n年齢: " + age + "\n";

と書くところを、

const name = '名前';
const age = 25;
const s = `名前: ${name}
年齢: ${age}
`;

と書くことができます。

いくつか限定してご紹介しましたが、ES6の新しい機能はこのほかにもたくさんありますので、検索して調べてみてください。

(2022/2/2 中島)

Posted in テクニカルコラム.