ECMAScriptとは?
JavaScriptは1995年にWebで実行できるスクリプト言語として開発されたそうですが、ブラウザベンダーによる独自の拡張が多く互換性が低かったので、ブラウザ間で動いたり動かなかったりがあったのではないかと。
そこで、Ecmaインターナショナルが中心となり、JavaScriptの中核仕様を抜き出して標準化したのがECMAScriptのようです。
・ECMAScript 2015(ES6)の概要と次世代JavaScriptの新たな機能 | HTML5Experts.jp
言語仕様を整理していきましょうということみたいです。
ES2015(ES6)で追加された仕様
ECMAScript 6th editionの6を取ってECMAScript 6(ES6)と呼ばれていますが、正確な呼称はECMAScript 2015(ES2015)というようです。
- let・constキーワードによる変数宣言
- classキーワードによるクラス宣言
- 関数の引数のデフォルトパラメータ(Default Parameters)
- 関数の可変長引数(Rest Parameters)
- アロー関数(Arrow Functions)
- ジェネレータ関数(Generator Functions)
- 配列展開(Array Spread)
- 分割代入(Destructing Assignment)
- 文字列のテンプレートリテラル(Template Strings)
- importとexportによるモジュール構文(Module)
など、かなり新しい文法が追加されています。
ブラウザのJavaScriptエンジン(JavaScript runtimeとも言う?)
ブラウザがJavaScriptを実行できるのは、JavaScript runtimeがECMAScriptの構文を解釈して実行しているためのようです。
ただ、このJavaScript runtimeがブラウザごとに異なるようです。
ブラウザ | レンダリングエンジン | JavaScript runtime |
---|---|---|
Chrome | Blink | V8 |
Opera | Blink | V8 |
Safari | Webkit | JavaScript(Nitro) |
PhantomJS | Webkit | V8 |
Firefox | Gecko | SpiderMonkey |
IE | Trident | Chakra |
・PhantomJSと各ブラウザのJavascriptエンジンまとめ | tsuchikazu blog
つまり、ES6使いたいけどES5までしか対応できてないブラウザでは、ES6が使えないことになります。
でも、ES6使って開発したいという場合、
完全ではないですが、Babel(旧6to5)などのトランスパイラやpolyfillライブラリを活用する方法があります。
トランスパイラ
新しい文法を使ったソースコードをES5 または ES3 までの文法に置き換えるソースコード変換ツール。
- Babel
- buble
- Traceur Compiler
- Rollup
など種類が結構あるようです。
AltJS(Alternative JavaScript)
AltJS(Alternative JavaScript)とは、その名の通りJavaScriptの代替言語です。JavaScriptと同等以上の機能を提供している言語ということらしいです。
- TypeScript
- CoffeeScript
- Dart
- Haxe
- jsx
コンパイルされることでJavaScriptのコードになるようです。
・WEB+DB PRESS Vol.87のECMAScript 6特集を読んだ(+TypeScript) - dackdive's blog
・レトロエンジニアのための近代Webフロントエンド事情 - Qiita
ES6開発環境を作ってみる
Node.jsがインストールされている必要があり、npmコマンドも必要になってきます。 Node.jsをインストールし、npmコマンドで必要なものをインストールしていく感じでしょうか。
- Node.js
- Babel
- Polyfill
- webpack
- Mocha
- Karma
⇩ 下記サイトが詳しいです。
いきなりハマる
Babel6になって、いろいろ仕様が変わったようで、導入の仕方が変わったようです。
これを知らずに、かなりハマりました。
・babel6での変更点 Gulp・Webpackの設定 - Qiita
まずは、コマンドプロンプトを開きます。babel-cliをインストールします。今回は管理者ではなく、ユーザーでコマンドプロンプトを開いてます。
npm install --global babel-cli
下記コマンドでbabelのバージョン情報が表示されれば、インストール成功です。
babel --version
npmでnodeのモジュール(今回だとbabel-cli)をグローバルにインストールすると、
C:\Users\ユーザー名\AppData\Roaming\npm\node_modules
にnode_modulesというフォルダの中にモジュールが追加されていくので、環境変数にパスを追加しておくと nodeのrequire先のトラブルが解消できるようです。
今回は、設定しませんでしたが設定しておきたいと思います。
・Windowsのnode.jsでrequire検索パスの初期値を自動設定する - Null and void
次に、package.jsonファイルを作成します。プロジェクトは package.json で管理することが一般的のようなので、ない場合は作成しておけば間違いないかと。
適当な場所にフォルダを作成(今回はC:¥ES6を作成)しておいて、cdコマンドでそのフォルダ(プロジェクト)の場所まで移動したら、
npm init
コマンドを実行します。対話式で プロジェクト名やユーザー名, バージョン番号, その他諸々聞かれますが、今回はEnter連打で。これでpackage.jsonファイルが用意されます。
「babel-preset-es2015」をインストール
BabelにES2015のコンパイルの処理を行わせる「babel-preset-es2015」というプリセットをプロジェクトにインストールします。--save-devはinstallしたlibraryの情報を自動でpackage.jsonに書いてくれるoptionのようです。
npm install babel-preset-es2015 --save-dev
.babelrcファイルの準備
.babelrcという設定ファイルを用意し、そこにBabelでさせたい処理をプリセットやプラグインとして登録しておく必要があります。
echo '{ "presets": ["es2015"] }' > .babelrc
このような、構成になっていればOK。
このフォルダ(プロジェクト)に、ES6で記述したファイルを作成し保存します。
"use strict"; class User { constructor(name) { this.name = name; } greet() { return 'Hello, My name is ' + this.name; } } var bob = new User("Bob"); bob.greet();
ファイルを作成したら、ES5に変換したファイルを下記コマンドで作成します。(トランスパイル実行)
babel test.js -o test-es5.js
test-es5.jsファイルが作成されました。
ファイルの中身を確認すると、ES5に変換されてるようです。
"use strict"; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var User = function () { function User(name) { _classCallCheck(this, User); this.name = name; } _createClass(User, [{ key: "greet", value: function greet() { return 'Hello, My name is ' + this.name; } }]); return User; }(); var bob = new User("Bob"); bob.greet();
Babelでトランスパイル成功です。
Polyfillのインストール
Babel でトランスパイルすることで、古いブラウザでも動作する Javascript を出力できるようになったのですが、古いブラウザの標準オブジェクトの中には ES6 に対応していないものがあります。 そのために標準オブジェクトを拡張する Polyfill を導入するようです。
npm install babel-polyfill --save-dev
標準オブジェクトを拡張することは、既存の環境と互換性を失うことになります。Polyfill を導入するときは、標準オブジェクトを拡張していることをちゃんと認識したうえで使う必要があるようです。
webpackのインストール
webpack は WebApp に必要なリソースの依存関係を解決し、アセット(配布物)を生成するビルドツール(要するにコンパイラ)です。JavaScript だけでなく、CoffeeScript や TypeScript、CSS 系、画像ファイルなどを扱うことができます。
ということで、インストールします。webpack は様々形式のデータを扱うのに、プラグイン形式で対応しており、babel を使う場合は babel-loader を使います。webpackはグローバルでインストールします。
npm install -g webpack
npm install babel-loader --save-dev
interpret に対応しているツール(webpackはinterpretをロードしている)に関しては、babel-register をインストールすれば、もれなく ES6 にも対応できるようです。
npm install babel-register --save-dev
webpackの設定ファイル(通常はwebpack.config.js)をプロジェクト直下に作成します。
webpack.config.babel.jsという名前にしておくと、babelなコードとして読んでくれる(webpackはinterpretをロードしているため。このbabelにも.babelrcの内容は適用される)ようです。
const path = require("path") module.exports = { // どのファイルをビルドするのかを指定。複数可。 entry: { test: './src/test.js', main: './src/main.js', }, // 出力するファイル名と出力先パス output: { path: path.join(__dirname + '/web'), filename: '[name].js' }, // トランスパイルされる前のjsファイルとトランスパイル後のjsファイルのソースマップ devtool: 'inline-source-map', // module module: { loaders: [{ // .js のファイルに対して test: /\.js$/, include: [ path.join(__dirname + '/src'), path.join(__dirname + '/test'), ], exclude: /node_modules/, loader: 'babel-loader', // loader でローダの指定。( babel-loader を使用して babel でトランスパイルする) }] } }
フォルダの構成を変更します。srcフォルダの中にES6で記述されたtest.js、main.jsを作成しておきます。webフォルダにはindex.htmlを作成し、
<html> <head> <meta charset="utf-8"> </head> <body> <script src="main.js"></script> <script src="test.js"></script> </body> </html>
としておきます。
webpackコマンドコマンドを実行します。
webpack
index.htmlをブラウザで表示し、デベロッパーツールの『console』を確認します。
何故か、main.jsの内容は読み込まれてますが、test.jsの内容が反映されない(涙)。
MochaとKarmaについてはまたの機会にトライしてみたいと思います。
追記
test.jsの内容が間違ってました。returnじゃConsoleに表示されないってことですね。
訂正前のtest.js
"use strict"; class User { constructor(name) { this.name = name; } say() { return 'Hello, My name is ' + this.name; } } var bob = new User("Bob"); bob.say();
訂正後のtest.js
"use strict"; class User { constructor(name) { this.name = name; } say() { console.log('Hello, My name is ' + this.name); } } var bob = new User("Bob"); bob.say();
⇩ フォルダ構成など維持したままコンパイルする方法は下記サイトへ
・Webpackで複数のファイルをそのままバンドルする - はらへり日記
今回はこのへんで。