• Home
  • JavaScript - ES2015入門

JavaScript - ES2015入門

JavaScriptの歴史について

JavaScriptを学習するにはその歴史についても少し知っておいた方が理解が進むでしょう。 というのもJavaScriptはとても複雑な歴史を歩んできておりその歴史の影響を受け、Node.jsなどのサーバーサイド言語や今のブラウザーで動くJavaScriptがあるからです。 また、Node.jsもブラウザーでのJavaScriptも今でも微妙に書き方が違うところがあり、そこがJavaScriptの歴史を知らない初学者を苦しめることがあります。

まずはJavaScriptの歴史をサクッと復習しましょう。

CommonJS

JavaScriptは元々ブラウザー上でテキストや画像を動かすなど、ちょっとしたプログラムを動作させるものだったので言語として不十分なところがありました。 例えば、ES2015未満のJavaScriptでは他の言語では当たり前のようにできる、他のライブラリやモジュールを読み込む機能がありませんでした。

C言語で言うとこういった文法ですね

#import <stdio.h>

これまでのJavaScriptは以下のようにHTMLであらかじめJavaScriptを読み込んでおく仕様だったので言語ファイル内で読み込む必要がなかったのかもしれません。

<script src="./jquery.js"></script>
<script src="./jquery-modal-video.js"></script>

ただしサーバーサイドではHTMLは存在しないので、JavaScript側で他のライブラリを読み込む方法を決めておく必要があります。 そこでCommonJSはサーバーサイドやその他の環境でJavaScriptが動くように改めてJavaScriptの仕様を決めるために誕生しました。 その際にCommonJSでは以下のようにファイル内で他のライブラリやファイルを読み込む仕様になりました。

const fs = require('fs');

もしかすると読者の方の中にはこのrequireというJavaScriptの文法を見たことがある人もいるかもしれません。 これはまさにCommonJSから来ています。 こういったrequireを使って他のファイルを読み込む仕組みをモジュールシステムといいます。

Node.js

こうしたCommonJSの仕様をもとに2009年、サーバーサイドで動くJavaScript(Node.js)が誕生しました。 Node.jsは初めこそCommonJSの仕様にのとっていたのですが次第にCommonJSの仕様から外れていきます。

npm

npmはNode.jsをインストールすると同時に使えるようになるパッケージマネージャーツールです。 npmは今となってはフロントエンドの開発にも必須なツールとなっていますが元々はサーバーサイドのライブラリを管理するためのツールとして使われていました。

例えば以下のような書き方で外部に公開されているライブラリをインストールできます。

$ npm install fs-extra --save

次第にこのnpmの仕組みを利用してサーバーサイドだけではなくフロントエンドでもnpmでインストールしたライブラリを利用したいという考え方が生まれてきました。

この時に生まれたツールがbrowserifyというものでした。

この時代にはまだブラウザー側のJavaScriptは他のライブラリをimportする仕組みはなかったのですが、browserifyは一度コマンドを実行することによってモジュールのimport元とimport先をうまく結合させてそれを実現しました。 browserifyはCommonJSの仕様に則っていたため、requireをモジュール同士で解決することができました。 またnpmによってインストールされたパッケージもrequireによって一つのファイルに合体(バンドル)させることによって解決しました。

さらにその後、JavaScript同士の依存関係を解決するだけではなく、cssや画像もrequireできるWebpackというツールが出てきて今ではモジュールの解決にWebpackを使うのが一般的になっています。

ES2015

2015年にはJavaScriptの基本部分の使用を決めているEcmaScriptのES2015という新たな仕様がリリースされました。 EcmaScriptはCommonJSとは異なる仕様になりますが、この時にブラウザーでもやっとJavaScriptから他のモジュールを読み込むモジュールシステムが完成しました。

EcmaScriptでは以下のようにモジュールをインポートします。

import $ from './path/to/jquery.js';

requireではなく、importで他のモジュールをインポートする点がCommonJSとは異なります。 この違いが時に初学者を混乱させます。

ES2015以降

ES2015が策定される以前は仕様がECMA-262 第3.1版 で進化がしばらく止まっていたのですが、ES2015以降は毎年JavaScriptの仕様がリリースされるようになりました。 毎年以下のように新しい仕様が追加されています。

  • ECMAScript2015(ES6)
  • ECMAScript2016(ES7)
  • ECMAScript2017(ES8)
  • ECMAScript2018(ES9)
  • ECMAScript2019(ES10)
  • ECMAScript2020(ES11)

ES2015以降のJavaScriptの文法について

ここでES2015以降のJavaScriptの文法について学習していきましょう。

アロー関数

まずはアロー関数です。アロー関数という名前ですが実際には普通の関数と考えていただいて差し支えありません。

const sum = (a, b) => a + b;
const value = sum(3, 4)
console.log(value); // 7

ただし、これまでにJavaScriptの関数に存在したthisの束縛がありません。 例えば以下のコードを見てみましょう。

const obj = {
  name: 'daigo',
  sayName: function () {
    console.log(`my name is ${this.name}`);
  }
}

この場合、obj.sayName()を実行するとmy name is daigoと出力されます。これはこの関数が、objに束縛されているからです。

一方アロー関数に書き直した場合はどうでしょうか?

const obj = {
  name: 'daigo',
  sayName: () => {
    console.log(`my name is ${this.name}`);
  }
}

この場合、アロー関数のためthis.nameがobjに束縛されておらずobj.sayName()を実行するとmy name is までの出力になります。 このようにthisに対する縛りが変わってくるため、普通の関数とアロー関数ではそこを意識してかき分けるといいでしょう。 特にthisに依存しない関数の場合はアロー関数を使うような感覚でいいと思います。

let, const

またES2015から変数宣言をする際にvarではなくletconstを使うようになりました。

let

letとはスコープ内で有効な変数を定義する時に使います。スコープとは関数スコープやifやforのスコープを指します。 例えば以下の例を見てみましょう。

let a = 'test';

if (true) {
  let a = 'test2';
}

console.log(a)

この場合、console.log(a)の出力結果はどうなると思いますか? 答えはtestになります。 ifのスコープ内でletで宣言された変数はifの中でのみ有効のため、例え同じ変数名で上のスコープで宣言されていたとしてもその変数には影響しません。 それを保証するのがletになります。

const

constとはletのようにスコープ内でのみ有効な変数という点では変わりがないですがさらに書き換え不可能な変数となります。 例えば以下のような書き方だと値を書き換えてしまっているため文法エラーになります。

const name = 'daigo';

name = 'steelydylan';

ただし、オブジェクトのプロパティは以下のように書き換えができます。

const obj = {
  name: 'daigo',
  sayName: () => {
    console.log(`my name is ${this.name}`);
  }
}

obj.name = 'steelydylan';

Class

またES2015からクラス宣言もできるようになりました。それまでは以下のようにprototypeチェーンというものを利用してクラスを擬似的に実現していました。

function Character (name) {
  this.name = name;
}
Character.prototype.sayName = function () {
  console.log(`my name is ${this.name}`);
}

const character = new Character('daigo');
character.sayName();

ES2015からは以下のようにClassで書くことができます。

class Character {
  constructor(name) {
    this.name = name;
  }

  sayName() {
    console.log(`my name is ${this.name}`);
  }
}

const character = new Character('daigo');
character.sayName();

機能がまとまってみやすくなりましたね。

まとめ

今回はES2015以前に登場した仕様などを紹介しました。 受講者の皆さんがネット上で情報を探す際に、JavaScriptの昔の文法やモジュールについての情報に惑わされなくなれば幸いです。

実はまだES2015以降の文法にはPromiseやasync await、ジェネレーターなど覚えるべき文法はたくさんあります。 次のレッスンではより詳しくJavaScriptの文法を見ていきましょう。

学習状況

ログインすることで学習状況を確認できます