mosya
mosya Business はこちら

JavaScript - JavaScriptの歴史とモダンな書き方について

JavaScriptの歴史について

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

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

ライブラリが読み込みづらい問題

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

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

#import <stdio.h>

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

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

CommonJSの登場

JavaScriptをブラウザーだけではなく他の環境(例えばサーバー)でも動かしたいというニーズが出てきました。
ただしサーバーサイドでは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の仕様から外れていきます。
そのためNode.jsで動くJavaScriptとブラウザーで動くJavaScriptでは文法が微妙に違うところがあります。

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の昔の文法やモジュールについての情報に惑わされなくなれば幸いです。

Authored by

筆者の写真

Godai@steelydylan

Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。

ReactやTypeScriptなどの周辺技術が学べる
オンライン学習サービスを作りました!

詳しくはこちら
mosya

mosyaはオンラインでHTML,CSS,JavaScriptを基本から学習できるサービスです。現役エンジニアが作成した豊富なカリキュラムに沿って学習を進めましょう。

© 2023 - mosya. All rights reserved.