プログラマ・アゲイン blog

還暦を過ぎたけどプログラマ復帰を目指してブログ始めました

JavaScriptの入門書 js-primer 初心者の読み方

JavaScriptの勉強をしています。「開発環境としてVisual Studio Codeを導入しました」でも書いたのですが、Kindle本を読んで勉強していました。

ところが、たまたま初心者のためのJavaScript解説サイトを紹介しているページがあり、「js-primer」を読んでみました。まだ読み切ったところですが、とても良かったです。目から鱗のことがたくさん書かれています。

先ずは内容の紹介と、実際に初心者としてやってみて気が付いたことをまとめようと思います。

 

JavaScript初心者のための解説サイト

JavaScriptの勉強をしています。JavaScript②でも書いたのですが、Kindle本を読んで勉強していました。

ところがたまたま以下のページで、初心者のためのJavaScript解説サイトが紹介されていました。二つ紹介されているのですが、試しに解説サイトの一つ目を読み切ったところですが、とても良かったです。次は二つ目を読んでみたいと思います。

qiita.com

js-primer JavaScriptの入門書

最初に読んでいるのは、【js-primer】のサイトです。

jsprimer.net

書籍の概要

「この書籍について」では、以下のように記述されています。

「これからJavaScriptに入門したい人が、ECMAScript 2015以降をベースにして一からJavaScriptを学べる本です。
プログラミングをやったことがあるが、今のJavaScriptがよくわからないという人が、 今のJavaScriptアプリケーションを読み書きできるようになるように書かれています。」

初心者には、読んでいくだけで整理されてJavaScriptが勉強できそうです。

書籍の目的

また、「はじめに」では、本書の目的が記述されています。

「この書籍の目的は、JavaScriptというプログラミング言語を学ぶことです。 先頭から順番に読んでいけば、JavaScriptの文法や機能を一から学べるように書かれています。」

JavaScriptの文法といった書き方を学ぶことも重要ですが、実際にどのように使われているかを知ることも目的にしています。」

「また、JavaScriptは常に変化を取り入れている言語でもあり、言語自身や言語を取り巻く開発環境も変化しています。この書籍では、これらのJavaScriptを取り巻く変化に対応できる基礎をつけていくことを目的としています。」

さらに、目的ではないことなども記述されており、しっかりしているので安心して読めます。

js-primerの構成

構成は、二部構成になっています。

第一部:基本文法では、JavaScriptの基本的な文法やビルトインオブジェクトの使い方が紹介されています。文法だけではなく、現実の利用方法についても言及されています。現実の利用方法から、"var"は使用せずに"let"や"const"を使うべきなど、初心者では気が付かないことが理由も含めて書かれています。

第二部:ユースケースでは、第一部の基本文法で学んだことを応用し、具体的なユースケースを元に学んでいきます。「Ajaxで通信」「Node.jsでCLIアプリ」「Todoアプリ」の小さなアプリケーションを例に、現実と近い使い方が解説されています。

第一部の感想

第一部を読んでみて、記述されている内容と量が豊富で、とても勉強になりました。

確かに、「クラス」「例外処理」あたりからが難しく感じ、初心者である私には頭に入ってこなくて眠くなることもありましたが。(^ ^;)

ともかく、頑張って一通り読み切って、第二部のユースケースを通じて理解を深めようと思っています。

第二部 Ajaxで通信

第一部は、眠くなりながらも何とか読み通すことができました。

しかし、第二部では実際に手を動かしてみる必要がある為、初心者ならではの悩みが出てきました。実際にやってみる過程で出てきた悩みを、以下にまとめてみました。初心者すぎる悩みなので、大目に見てやってください。

HTMLファイルの用意

最初のユースケースである「Ajaxで通信」に、以下のようなHTMLファイルとJSファイルを作成するように書かれています。

<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>Ajax Example</title>
  </head>
  <body>
    <h2>GitHub User Info</h2>
    <script src="index.js"></script>
  </body>
</html>
console.log("index.js: loaded");

初っ端の、ファイル名を付けるところから躓いてしまいました。

JavaScriptの方は、"index.js" というファイル名なのがはっきりしているのですが、HTMLの方は特に記述されていません。普通に考えれば、HTMLなので "index.html" なのでしょうが、如何せん初心者なもので "ajaxexample.html" と付けてしまいました。

当然、後のテストで動きません。後で、"index.html" に変更しました。

また、ファイルを適当なユーザー・ディレクトリー "c:\Personal\HTML\JavaScript" に保存しました。これは、次のローカル・サーバーの起動で引っかかってきます。

ローカル・サーバーの起動

前述のHTMLとJavaScriptの稼働をテストするために、ローカル・サーバーを稼働させます。ローカル・サーバーは、サーバーサイドJavaScript実行環境の Node.js をベースに、書籍用に作成された @js-primer/local-server というローカルサーバーモジュールで稼働させます。ダウンロードと同時に実行する npxコマンドが紹介されていますが、何回もテストするでしょうし、そのたび毎にダウンロードするのも無駄だと思うので、ダウンロードと実行を分けることにしました。

なお、以降のコマンドは、Windowsのコマンド・プロンプトで入力しているので、実際のプロンプトは c:\Users\ユーザー名> ですが、省略して "$" にしてます。

ダウンロードは、npmコマンドで一度だけ行い、インストールします。インストールは、C:\Users\ユーザー名\AppData\Roaming\npm 配下にされます。

$ npm install --global @js-primer/local-server

テストしたい時は、インストールされた上記ディレクトリの .cmd ファイルを実行することで、行われていると思います。コマンドは、以下のようになります。

$ js-primer-local-server
HTMLファイルの読み込み

早速、FireFox に "http://localhost:3000" を指定してテストしてみましたが、「Cannot GET /」のエラー・メッセージが出て動きません。

デバッカーを見ても、「このページにソースはありません。」と出るので、HTMLファイルを読み込めていないことが判ります。単純ですが、理由は以下の2つだと考えました。

  1. 読み込むHTMLファイルのディレクトリが指定されていない
  2. 読み込むHTMLファイル名が指定されていない

2.については、URLを「http://localhost:3000/ajaxexample.html」にしてもよいのですが、取り敢えず "index.html" にすればよいと思いました。

問題は、1.の方です。どこかにディレクトリを指定する設定ファイルがあるのではないかと探しましたが、見つけられませんでした。

いろいろ探していると、C:\Users\ユーザー名\AppData\Roaming\npm\node_modules\@js-primer\local-server\README.md の中の記述で、以下の起動の仕方が書かれています。

Usage
  $ npx @js-primer/local-server [<directory>]

ということで、以下のように起動する時にディレクトリを指定すれば、ちゃんと動きました。

$ js-primer-local-server c:\Personal\HTML\JavaScript

また、あらかじめ cdコマンドで c:\Personal\HTML\JavaScriptディレクトリに移動しておいてから、ディレクトリ指定せずにローカル・サーバーを立ち上げても大丈夫でした。

因みに、ローカル・サーバーを終了させるのは、Ctrl+C で次のメッセージが出るので、"y" を返答することで終了します。

バッチ ジョブを終了しますか (Y/N)?

因みに、「Ajaxで通信」で躓いたこれらのことは、3つ目のユースケースである「Todoアプリ」で説明されてました。なので、最初に「Todoアプリ」から勉強してみるのもありかと思います。(早く気が付けばよかった (T T) )

第二部 Node.jsでCLIアプリ

2つ目のユースケース「Node.jsでCLIアプリ」も、ちょっと苦労しました。

commanderライブラリの導入

最初の躓きは、commanderライブラリの導入でした。以下のコマンドで、ユーザーのディレクトリーに導入しました。

C:\Users\ユーザー名>npm init --yes
C:\Users\ユーザー名>npm install commander@2.9

しかし、これでは別のディレクトリーに作成したJavaScriptが実行できません。以下のエラーが出ます。

C:\Users\ユーザー名>node commander-flag.js --foo
internal/modules/cjs/loader.js:638
    throw err;
    ^

Error: Cannot find module 'C:\Users\HiroshiNaruo\commander-flag.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)

ということで、JavaScriptファイルを配置しているディレクトリーに移動して、commanderライブラリを導入し直すことにしました。その時に、以下のページを参考にさせていただきました。

qiita.com

markedパッケージの導入

「アプリケーション開発の準備」で、npm installコマンドでパッケージを導入する方法が記述されています。そこには、以下の記述があります。

「通常のnpm installコマンドは実行したカレントディレクトリにパッケージをインストールしますが、--globalフラグを加えるとパッケージをグローバルインストールします。 グローバルインストールされたパッケージのコマンドは、nodeコマンドやnpmコマンドと同じように、任意の場所から実行できます。」

そこで、markedパッケージも同じようなものかと思い込み、--globalフラグを付けて導入してみました。

$ npm install -g --save marked@0.6

しかし、この方法では以下のエラーになって実行できません。

c:\Personal\HTML\JavaScript>node read-file.js sample.md
read-file.js
internal/modules/cjs/loader.js:638
throw err;
^
Error: Cannot find module 'marked'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)

ということで、commanderライブラリと同じく、以下のコマンドで導入し直すことにしました。

c:\Personal\HTML\JavaScript>npm install --save marked@0.6
ユニットテスト

最後のユニットテストでも、引っかかってしまいました。npm testを実行しても、以下のエラーになってテストが通りません。

  1) converts Markdown to HTML
  0 passing (33ms)
  1 failing

  1) converts Markdown to HTML:
      AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
  assert(md2html(sample) === expected)
      + expected - actual
      -false
      +true
      at Context.it (test\md2html-test.js:11:5)

sample.mdファイルを読み込んで、htmlへの変換処理した結果とexpected.htmlファイルの中身とを比較しています。ecpected.htmlファイルは、sample.mdファイルを元に手でmarkdownからhtmlに変換して作成しました。見た目は正しいと思います。しかし、いくらexpected.htmlファイルを作成し直したり、console.logで表示させて確認しても、違いが判りません。

そこで、sample.mdファイルをmd2html処理して、expected.htmlファイルを書き出す以下のJavaScriptを作成しました。

const fs = require("fs");
const path = require("path");
const md2html = require("./md2html");
const sample = fs.readFileSync(path.resolve(__dirname, "./sample.md"), "utf8");
const expected = md2html(sample);
fs.writeFileSync("./expected.html", expected);

手で作成したexpected.htmlファイルと実際に書き出されたexpected.htmlファイルを比べてみると、259バイトと250バイトで9バイトの違いがありました。サクラエディタで比較すると、改行記号のところで引っかかりました。

何のことはなく、手で作成したファイルの改行コードは「CRLF」で、プログラムで作成したファイルの改行コードは「LF」だったのです。

サクラエディタで入力改行コードを「LF」にしてexpected.htmlファイルを作成し直したところ、無事にテストが通りました。

第二部 Todoアプリ

ユースケースのTodoアプリでは、スペル・ミスで動かないなどの初歩的な間違いはありましたが、説明も丁寧にされているので問題なく学習を進めることができました。また、MVCリファクタリングのイメージもつかめました。ただし、内容を理解できたということではなく、あくまでも学習できたというレベルではありますが。(^ ^;)

一点時間がかかったのは、「Todoアイテムの更新と削除を実装する」ところのApp.jsの修正のところでした。修正する部分が最初判らず、ゆっくりソースを読みながら処理内容を整理していたので、時間がかかりました。おかげで勉強になりましたが。

一通り終わって、最後の部分の「セクションのまとめ」に、2点課題が載っています。その課題のうち、「アプリケーションのライフサイクルを意識する」で「mountとunmountを実装」の例が載っており、index.jsに組み込みました。そこで、unloadイベントで呼ばれるunmountの処理はどのように確認するか、についてはこれから勉強です。

最後に

js-primerを勉強してみて、初心者の私としては大変良かったと思います。

確かに、途中難しいところもあるのですが、内容も丁寧で新しい情報に基づいているので、JavaScriptを直ぐに書くことはできなくても、少し読むことはできるようになった気がします。