Subterranean Flower

【連載記事】JavaScriptでプログラミングを学ぶ その1:基礎と文法

Author
古都こと
ふよんとえんよぷよぐやま!!!

JavaScriptは昔からあるプログラミング言語ですが、特に近年ではウェブ技術の盛り上がりにともない、JavaScriptの人気も上昇しています。

JavaScriptを学ぼうとすると、数多くの書籍・記事を見つけることができます。しかしながら、それらの多くはすでに他の言語でプログラミングを学習している人向けであったり、JavaScriptをもうすでに使っている人向けの小さなアドバイスであったりします。よってプログラミング初心者がJavaScriptを学ぼうとすると、様々な困難に直面します。特に、体系的にまとまった初心者向けの文献を探すのは、骨が折れます。

そこで、この連載記事では、いままでプログラミングを学んだことがない人を対象に、JavaScriptによるプログラミングを習得してもらうことを目標にしています。プログラミングの楽しさを、ぜひ体験してください。

連載目次

  1. 基礎と文法(この記事)
  2. 関数
  3. 配列とオブジェクト
  4. オブジェクト指向
  5. データ構造とアルゴリズム
  6. HTMLとDOM(予定)
  7. 未定

プログラミング言語JavaScript

プログラミング言語の中で、JavaScriptはどちらかというと新しい部類に入ります。パソコンとインターネットが世の中に普及して、ウェブページを見るのが一般的になった頃に登場しました。

もともとはウェブページ上でプログラムを動作させるために作られましたが、近年ではパソコン上でブラウザを介さず実行したり、サーバ側のプログラムとして採用されるケースも増えています。

JavaScriptは「インタプリタ型言語」と呼ばれるものの一種で、プログラマがプログラムを手動でコンパイル(※コンピュータが理解できる形式に変換)する必要がなく、実行時に逐次的に解釈してくれます。

ブラウザさえあればどこでも動き、最近ではサーバサイドでも使われているという実行環境の広さと、コンパイル不要という気楽さを兼ね備えた言語で、初めに学ぶプログラミング言語としては扱いやすい性質を持っています。

この連載について

目的・目標

JavaScriptを学ぶ目的は様々あるでしょう。「ウェブページをリッチにしたい!」「Reactを使ってウェブアプリを作りたい!」などです。ですが、残念ながらこの連載ではそれらは扱いません。

この連載では、JavaScriptを使って、JavaScriptによるプログラミングそのものを学んでいただきます。JavaScriptの基本的な文法について、プログラミングを構成する概念について、あるいはデータの扱い方について、様々な切り口からJavaScriptプログラミングを取り扱います。どうしても地味な内容になりますし、「とりあえずなんとなくJavaScriptを使えるようになりたい」という人の期待にはこたえられないかもしれませんが、確実に実力はつきます。

単にわけもわからずJavaScriptで何かを動かすだけなら、すでにネット上に大量に情報があふれています。それで大半の人の需要は満たせるでしょう。しかし、世の中にいるのはそういった人だけではありません。きちんと基礎知識をつけたいという人もいます。何か具体的な目標を持っている人にとって、プログラミング自体の概要を学ぶというのは遠回りになるかもしれませんが、愚直に学んでいきたいという人も存在するのです。

この連載では、おおまかにですが、大学の1年生で学ぶ程度の基礎的な内容を取り扱います。と言ってもプログラミングについてだけなので、数学や論理学などの要素を本格的に扱うつもりはありません。プログラミング外の知識が必要になる場合は、その都度解説するので、安心してください。

開発ターゲット

先述の通り、JavaScriptの実行環境は様々です。しか、JavaScriptでプログラミングを学ぶ上では、どこか一点に環境を絞った方が効率的です。

「ブラウザを使わずパソコン上で動かす」、プログラミングにおいては、これが本来は最適です。ですが、ブラウザなしで動かすには、コマンドライン(ターミナル)に慣れ親しむ必要があります。プログラミング初心者にとって、コマンドラインの黒い画面は恐怖でしかありません。加えて、プログラミングとコマンドラインの両方を習得する必要が出てきてしまい、学習の焦点があいまいになります。

よって、この連載では、次善策となりますが、ブラウザとテキストエディタだけで完結する方法を取ろうと思います。ブラウザは普段から使用していますし、テキストエディタは誰にでも動かせる単純なものです。普段から使っている環境で、気楽にプログラミングしていきましょう。

プログラミングの前準備

ブラウザの準備

ブラウザを使ってJavaScriptの開発をするにあたって、当然ですがブラウザが必要になります。あなたが今このブログを見ているブラウザを使っても構いませんし、新しいブラウザを入れても良いです。

この連載ではChromeを使っていることを前提に話を進めていきます。Firefoxでも同じことができるので、そちらでも大丈夫です。SafariやEdgeなどでも、やろうと思えばできるはずです。

どれを入れればいいか迷ったら、Chromeを入れましょう。

エディタの準備

JavaScriptを編集するには、テキストエディタが必要になります。テキストエディタはメモ帳などでもいいのですが、プログラミング向けのエディタを入手した方が、各種補助機能が搭載されていて、作業がやりやすくなります。

今回はAtomというエディタを使います。Atomは以下のURLからダウンロードできます:

Atomをダウンロードして、インストールしてください。Macだと生のAtom.appが出てきますが、Applicationsフォルダに入れておくと良いと思います。

Atomのセットアップ

インストールできたら、さっそくAtomを起動してください。Atomでの開発環境を整えます。

JavaScriptモードはAtomに最初から入っていますが、ブラウザで動作確認をする際のウェブサーバ機能が同梱されていないので、導入します。

まずAtom→Preferences(WindowsならFile → Settings)を開きます。開いた設定の中から「Install」を選びます。

すると右側にパッケージ(拡張機能)のインストールメニューが出てきます。「Search packages」という検索欄があるので、そこで「atom-live-server」と入力して、Enterを押してください。

するとatom-live-serverというパッケージが出てくるので、Installを押して、インストールが終わるのを待ってください(それなりに時間がかかると思います)。インストールが完了したら、準備は完了です。

また、必須ではありませんが、日本語のメニューが好みであるならば、japanese-menuも入れておくといいでしょう。

今回学ぶ内容

今回学ぶのは、JavaScriptの基本要素と文法についてです。「変数」や「条件分岐」など、プログラミングを学んだことがない人でも一度は聞いたことがあるでしょう。聞いたことがなくても安心してください。各要素について、それぞれ解説いたします。

しかし、これらのことだけではまだ高度なプログラムは組めませんので、今回の記事を読んだだけではいまいちピンとこないかもしれません。わからなければ「とりあえずそういうものだ」と保留しておいて、先に進んだときに何かがわからなくなったら、またこの記事に戻ってきてください。

Hello World!

では、さっそく始めていきましょう!

まず最初にすることは、作業フォルダを作ることです。ファイルはどこかに散らかしてもいいのですが、ひとつのフォルダにまとまっていた方が扱いやすいはずです。作る場所はデスクトップなどで構いません。フォルダ名は「jsprogramming」などでいいでしょう。

作業フォルダを作ったら、Atomでそのフォルダを開きます。File → Add Project Folderから、先ほど作った作業フォルダを開きます。

これでフォルダがAtomに認識されました!あとはここにファイルを追加していきます。もし間違って左側を閉じてしまっていたら、View → Toggle Tree Viewで再表示できます。

まずJavaScriptを実行するためのHTMLファイル(ウェブページ)を追加します。Atom上でフォルダを右クリックして、新しいファイル(New File)を作ってください。

ファイル名の入力画面が出てくるので、「index.html」と入力してください。このファイル名は固定です。Enterを押すとファイルが作成されます。

index.htmlが作成できたはずなので、その中に以下の内容を貼り付けて、保存(Ctrl + S / Command + S)してください:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JavaScriptでプログラミングを学ぶ</title>
    <script src="main.js" defer></script>
  </head>

  <body>
  </body>
</html>

左の12345…はただの行番号なので不要です。これはJavaScriptを実行するためのウェブページで、6行目で「main.js」というファイルを読み込んで実行します。今回はHTMLについては知らなくても良いので、解説はいたしません。詳しく知りたい人は各自調べてください。

次に「main.js」というファイルを作ってください。HTMLファイルで指定したファイル名ですね。この中にJavaScriptを書いていきます。

main.jsの中に、以下を貼り付けて保存してください:

'use strict';

// コンソールにHello World!を出力する
console.log('Hello World!');

保存できたら、Packages → atom-live-server → Start serverを選択します。少し待つとサーバが起動して、ブラウザが自動的に真っ白いページを開くはずです。ページが自動的に開かれなかった場合は、手動でhttp://127.0.0.1:3000/にアクセスしてください。

真っ白いページを開いたまま、Chromeなら「表示 → 開発/管理 → JavaScriptコンソール」を、Firefoxなら「ツール → ウェブ開発 → ウェブコンソール」を選んでください。コンソール画面が開かれるはずです。

そこに「Hello World!」と表示されているはずです。「Live reload enabled.」はatom-live-serverの表示なので気にしないでください。また、ここにfaviconがどうのこうのというエラーが出ることがありますが、それは無視してください。

出ない場合は、コンソールを開いたままページをリロードしてみてください。それでも出ない場合は、ちゃんとファイルを「保存」しているか確認してください。Atomのタブの右端に青丸がついていたら、「保存していない」合図です。

表示されましたか?おめでとうございます!あなたはプログラミングの第一歩を踏み出しました!

Hello World!解説

Hello Worldでは以下のコード(人間が読めるプログラムのこと。ソースコードとも言う)を貼り付けました:

'use strict';
 
// コンソールにHello World!を出力する
console.log('Hello World!');

プログラムは、基本的に上から下に順番に実行されていきます。また、各行に書かれているものを命令と呼びます。命令を上から順番に1行ずつ実行していき、最終行までたどり着けば終わりです。

まず1行目から見ていきましょう。1行目には’use strict’;と書かれています。これは「JavaScriptを厳格モードで実行せよ」という印で、基本的には1行目に書きます。厳格モードというと難しそうなイメージがありますが、その実態は「バグ発見モード」のようなもので、バグにつながる軽率なコードを見つけるとエラーを出してくれます。初心者ほどありがたい機能なので、よっぽどのことがない限り厳格モードにしておきましょう。

3行目はコメントと呼ばれるもので、これはプログラムに一切影響を与えない、全くの無意味なメモ書きです。コメントを使うには、スラッシュを2個続けて書きます。スラッシュ2個のあとは、行末までコメントになり、何を書いても無効です。純粋なコードだけでは「何をやっているのか」は人間にはわかりにくいものです。なので、コメント(メモ)を入れてわかりやすくするのが、プログラミングのテクニックのひとつとなっています。

4行目で、やっとプログラムらしい命令が出てきます。console.logは「コンソールに出力せよ」という命令です。console.logにHello World!という文字列を指定し、Hello World!を出力するように命令しています。

また、各行の末尾にはセミコロン(;)がついています。これは命令の区切りを表し、セミコロンまでがひとつの命令となります。セミコロンを省略しても動くときは動くのですが、あまり行儀のいい方法ではないので、基本的にはセミコロンをつけておきましょう。

値と変数

Hello World!の例では、文字列を出力しましたが、文字列だけではなく数値も扱うことができます。すでに気づいている人もいるかと思いますが、文字列はシングルクォート(’)で括ります。JavaScriptではたとえ1文字だけだとしても、「文字列」です。

一方、数値として扱いたい場合は、特に何かで括ることはありません。そのまま書けば動きます。main.jsを変更して保存してみてください:

'use strict';

// コンソールにHello World!を出力する
console.log('Hello World!');

// コンソールに42を出力する
console.log(42);

逆に文字列をシングルクォートでくくらないと、エラーとなります。注意してください。

これを実行する際、特に何もしなくともmain.jsへの変更を保存すればブラウザのコンソールへ反映されるはずです。反映されない場合はリロードしてみてください。また、一度サーバを止めてしまったのなら、ふたたびPackages → atom-live-server → Start serverでサーバを開始してください。

値(あたい)

文字列や数値といった、プログラミングで扱うデータのことを値(あたい)と言います。数値が値なのは直感的だと思いますが、文字列のことも値と呼びます。

例えば「10」は値ですし、「’Hi’」も値です。とにかくデータのことは全部「値」です。

演算と演算子

数値は各種演算が可能で、足し算(+)、引き算(-)、掛け算(*)、割り算(/)、余り(%)、累乗(**)などが使用できます。ここで+や-といった演算記号のことを演算子と言います。

また、数学のように括弧を使って優先順位を明示することもできます。

'use strict';

// コンソールに計算結果を出力する
console.log(1 + 2 * 3);

// 括弧を使った優先順位の明示
console.log((1 + 2) * 3);

文字列は結合演算子(+)が利用可能です。

'use strict';

// 文字列の結合
// HelloとスペースとWorld!を結合している
console.log('Hello' + ' ' + 'World!');

評価と式

プログラミングにおいては、計算して値を得ることを評価すると言います。例えば「1 + 2は3として評価される」「’Hello’ + ‘World’は’HelloWorld’として評価される」などという具合にです。

また、値として評価されるものを、と言います。先ほどの「1 + 2」や「’Hello’ + ‘World’」は式ですね。そして、少しややこしいですが、計算が入っていない単体の値も式となります。「1」も式ですし、「’Hello’」も式です。

値のデータ型

さて、ここで問題です。以下のコードの出力はどうなるでしょう?

'use strict';

console.log(12 + 34);
console.log('12' + '34');

3行目のconsole.logは、もちろん46が出力されます。これは簡単な足し算ですね。問題は4行目です。これはどうなるのでしょう。

シングルクォートで書かれたものは、それがなんであっても「文字列」です。よって数字が書かれていても、それは数値ではなく、「数字の書かれた文字列」となります。つまり文字列’12’と文字列’34’の結合となり、「1234」が出力されます。

このようにして、数値と文字列では、全く異なる役割が与えられています。この「数値」「文字列」といったデータの分類のことを「データ型」、あるいは単純に「」と言います。

JavaScriptの型は、以下の7種類しかありません(覚える必要はありません!):

  • undefined
  • null
  • 数値
  • 文字列
  • 真偽値
  • シンボル
  • オブジェクト

今のところ数値と文字列がわかっていれば問題ありません。JavaScriptではこれらたった7種の型を組み合わせてプログラムを作ります。

JavaScriptはあまり型にうるさい言語ではなく、型が表面に出てくることはほとんどありません。しかし内部的にはしっかり分類されていて、さきほどの「12 + 34」と「’12’ + ’34’」のように挙動に違いが出てきます。プログラミングをする際は、型をしっかり意識しておきましょう。思わぬバグの原因になります。

また、どうしても型を知りたい場合は「typeof」を使うことで、値の型を得ることができます。試しに数値と文字列の型を比べてみましょう。

'use strict';

console.log(typeof 12);
console.log(typeof '12');

これを実行してみます。

3行目の「12」はnumber(数値)、4行目の「’12’」はstring(文字列)と表示されました。数値と文字列で全くの別物ということがよくわかりますね。

変数

プログラミングにおいて、値を生のまま扱うことはほとんどありません。一般的には値に別名をつけ、その別名で利用していくことになります。この、値の別名を実現する仕組みとして変数というものがあります。数学にも変数という言葉がありましたが、あれと少し似ています。

例えば以下のようなコードがあるとします:

'use strict';

// なんの計算???
console.log(65/(1.7 * 1.7));

これはなんらかの計算をしていることはわかりますが、一目見ただけでは何をやっているのか、なかなかわかりません。そこで、変数を使って別名をつけてみます。

変数はconstというキーワードを用いることで作成できます。試しにやってみましょう:

'use strict';

// BMIの計算をしている!
const heightMeter = 1.7;
const weight = 65;
const bmi = weight/(heightMeter * heightMeter);
console.log(bmi);

これで先ほどの計算が、「身長1.7m、体重65kgの人のBMIの計算」ということがわかりやすくなります。プログラムの挙動としての違いはありませんが、読みやすくなりました。

const 変数名 = 値」という書式で書くことで、値に別名をつけることができます。ここでは「1.7」に「heightMeter」、「65」に「weight」という名前をつけています。変数名はアルファベットまたは一部の記号から始まる任意の名前で、先頭に数字を使うことはできません。変数名の途中や末尾に数字を入れることは可能です。また、変数名が複数単語になるときは、スペースは使えないので、単語の先頭を大文字にするという慣習があります。

イコールの右辺は値だけでなく式も利用可能です。計算式はその場で値として評価(計算)され、変数名が割り当てられます。

一度つけた別名は、好きなところで利用することができます。例えば上の例ですと、bmiを計算するときに変数weightと変数heightMeterを利用しています。さらに出力時に先ほど計算した変数bmiの値を出力しています。

このとき、変数を作ることを「変数を宣言する」、変数に値を割り当てることを「変数に値を代入する」といいます。先ほどの例では宣言と代入を同時に行っています。constキーワードを使った変数宣言では、必ず代入が必要です。

また、当然ながら変数も「プログラムは上から下に順番に実行される」の制約を受けます。例えば変数を宣言・代入する前に変数を使用することは不可能です。よって以下のコードはエラーとなります:

'use strict';

// 変数宣言前に変数を使おうとしている!
console.log(myVariable); // エラーが出る
const myVariable = 10;

変数を使うときだけに限りませんが、命令の実行順序には気をつけましょう。

そして、変数は同じ名前を多重宣言できません。以下のコードはエラーとなります:

'use strict';

const myVariable = 10;
const myVariable = 20;

変更可能な変数

constキーワードで変数を宣言・代入すると、変数の値を変更できなくなります。一度変数に値を代入すると、ずっとその値のままということです。

変数の宣言には実はもうひとつ種類があって、それはletキーワードを用いることで実現できます。letキーワードで宣言された変数は、後から何度でも値を変更可能です。

例えば以下のように使います:

'use strict';

// letキーワードで変数を宣言する
let myAge = 26;
console.log(myAge);// 26と表示される

// 値を変更する。
// letキーワードが必要になるのは宣言時だけ
myAge = 27
console.log(myAge); // 27と表示される

基本的にはconstと同じですが、letで宣言されると、変数に対して何度でも代入が行えます。後から変数に紐づける値を変更したいときに便利です。

また、letキーワードで宣言された変数の値が数値である場合、インクリメントデクリメントという機能が使えます。インクリメントは変数の値を1だけ増加させ、デクリメントは変数の値を1だけ減少させます。インクリメントは「変数名++」、デクリメントは「変数名–」と、変数名の後にプラスかマイナスをふたつ並べることで利用できます。

以下が使用例です:

'use strict';

// letキーワードで変数を宣言する
let myAge = 26;
console.log(myAge);

// インクリメント
myAge++; // myAge = myAge + 1;と同じ
console.log(myAge); // 27

// デクリメント
myAge--; // myAge = myAge - 1;と同じ
console.log(myAge); // 26

インクリメント「variable++」はvariable = variable + 1;と同じで、デクリメント「variable–」はvariable = variable – 1;と同じです。

インクリメント・デクリメントを前置する、プリインクリメント・プリデクリメントというものもあります。

'use strict';

// letキーワードで変数を宣言する
let myAge = 26;
console.log(myAge);

// プリインクリメント
++myAge;
console.log(myAge); // 27

// プリデクリメント
--myAge;
console.log(myAge); // 26

通常のインクリメント・デクリメント(ポストインクリメント・ポストデクリメントとも言う)とプリインクリメント・プリデクリメントの違いを説明するのは少し難しいので、ここでは省略します。使う機会が来たら説明します。

let変数を使用するとき、「今の値からxxxだけ増やす」「今の値からxxxだけ減らす」といった処理を使うこともあります。これは以下のように書くことができます:

'use strict';

let myAge = 26;

myAge = myAge + 2;
console.log(myAge);

myAge = myAge - 4;
console.log(myAge);

しかしこういった処理はよく使うので、短く書くことができるようになっています。「+=」や「-=」、「*=」という代入記号が使えます。以下のように使います:

'use strict';

let myAge = 26;

myAge += 2; // myAge = myAge + 2;と同じ
console.log(myAge);

myAge -= 4; // myAge = myAge - 4;と同じ
console.log(myAge);

また、letを使った変数宣言では、代入を行わない宣言が可能です:

'use strict';

// 宣言だけして代入はしない
let myAge;
console.log(myAge); // undefinedになる

とりあえず宣言だけして、代入は後から行うという場合に便利です。代入前でも変数は使用できますが、値がundefined(未定義)となります。使用してもエラーは出ませんが、意味のある値は得られません。

もうひとつの変数宣言

実はJavaScriptには3つめの変数宣言が存在します。名前をvarと言います。varはかつて使われていた変数宣言で、現在は使用しません。使用すること自体は可能ですが、初心者にとって予測不可能な挙動を示すこともあるので、使用するメリットはありません。

varについて詳しく知りたい人は「JavaScriptにおけるvar/let/constの使い分け」を読んでみてください。

真偽値

今までは数値と文字列という、我々にとっても馴染み深いものを扱ってきました。次に出てくるのはJavaScriptに存在する7つの型のうちの、真偽値という型の値です。

真偽値はtrue(真)またはfalse(偽)となる値で、物事が真かあるいは偽かを示す値です。俗にいう「フラグ」というやつでもあります。真偽値型の値も数値や文字列のように扱うことができます:

'use strict';

// 真偽値型の値を変数に代入する
// 鳥は飛べる。人間は飛べない。
const birdIsFlyable = true;
const humanIsFlyable = false;

console.log(birdIsFlyable);
console.log(humanIsFlyable);

真偽値型の値に対して可能な演算は、OR演算(||)とAND演算(&&)です。OR演算は片方でもtrueなら結果がtrueに、両方がfalseなら結果はfalseになります。AND演算は両方がtrueなら結果がtrueに、片方でもfalseならfalseになります。

OR演算は以下のようになります:

  • true || true // これはtrue
  • true || false // これはtrue
  • false || false // これはfalse

AND演算は以下のようになります:

  • true && true // これはtrue
  • true && false // これはfalse
  • false && false // これはfalse

試しに使ってみましょう:

'use strict';

// 真偽値型の値を変数に代入する
// 鳥は飛べる。人間は飛べない。
const birdIsFlyable = true;
const humanIsFlyable = false;

// OR演算
// これの結果はtrue
const someoneIsFlyable = birdIsFlyable || humanIsFlyable;

// AND演算
// これの結果はfalse
const everyoneIsFlyable = birdIsFlyable && humanIsFlyable;

console.log(someoneIsFlyable);
console.log(everyoneIsFlyable);

OR演算は片方でも成立しているか、AND演算は両方とも成立しているかを調べることができているのを確認できます。

また、NOT演算というものもあります。これは先頭に「!」をつけることで、真偽値を反転させることができるものです。

'use strict';

console.log(!true); // false

比較演算子

真偽値が最も効果を発揮するのは、比較演算子を使用したときです。比較演算子はその名の通り2つの値を比較する演算子で、評価結果が真偽値になります。比較演算子には以下のものがあります:

  • ===(等しい)
  • !==(等しくない)
  • >(大きい)
  • >=(以上)
  • <(小さい)
  • <=(以下)

===と!==は全ての型の値に対して使用できます。その他の比較演算子は主に数値に対して使用しますが、文字列を辞書順で比較することも可能です。

'use strict';

const comparison1 = 1 === 1; //true
const comparison2 = 2 !== 3; // true
const comparison3 = 10 < 100; // true

console.log(comparison1);
console.log(comparison2);
console.log(comparison3);

注意点として、比較演算子はあくまで演算子であり、「+」や「*」などと同じ働きをすると言うところです。つまり、比較演算子は不等式を表すものではありません。以下の例は誤りです:

'use strict';

// この使い方は誤り
const x = 5;
const comparison = 1 < x < 3;

console.log(comparison);

実行してもエラーは出ませんが、予期せぬ結果となります。こういう比較を行う際は、ひとつずつ比較して、AND演算(&&)で繋ぎます:

'use strict';

// この使い方が正解
const x = 5;
const comparison = 1 < x && x < 3;

console.log(comparison);

===と!==は対象となる値の型に制限はなく、文字列や真偽値などに対しても使用できます:

'use strict';

// テキストの比較
const comparison = 'abc' === 'abc';

console.log(comparison);

また、型が違うと異なる値となります。例えば「12」と「’12’」は等しくなりません:

'use strict';

// 数値と文字列の比較
// 結果はfalse
const comparison = 12 === '12';

console.log(comparison);

文字列に値を埋め込む

JavaScriptには、文字列の途中に値を文字列化して埋め込む機能があります。便利なのでちょっと触ってみましょう。

通常の文字列はシングルクォートを使って作りましたが、値を埋め込む時はバッククォート(`)を使います。この記号はshiftキーを押しながら@キーを押すと出てくるはずです。

シングルクォートをバッククォートに置き換えて、あとは文字列中に「${値}」と書き込むことで、値を埋め込むことができます。以下が例です:

'use strict';

const heightMeter = 1.7;
const weight = 65;
const bmi = weight/(heightMeter * heightMeter);

// バッククォートを使った、
// 文字列への値の埋め込み
console.log(`BMIは${bmi}です。`);

このとき、単なる値だけでなく、式も埋め込むことができます。

'use strict';

const heightMeter = 1.7;
const weight = 65;

// バッククォートを使った、
// 文字列への値の埋め込み
console.log(`BMIは${weight/(heightMeter * heightMeter)}です。`);

ただし、あまり複雑な式を埋め込むと読みにくくなるので、できるだけ変数を作ってそこに代入してから、文字列の中に埋め込んでください。

ここまでのまとめ

数値、文字列など、JavaScriptでは様々な値が存在します。値の種類は「型」と呼ばれていて、値の型によって挙動も異なります。数値型は基本的な計算ができますし、文字列型は文字列型同士の結合などができます。このとき、演算を行う記号のことを演算子と言いました。

値はそのまま使うことはまずありません。変数と呼ばれる別名を宣言して、そこに代入するのが一般的です。変数は一度宣言すれば好きな場所で使うことができ、値に名前がつくことでプログラムが読みやすくなります。変数の宣言にはconstとletがあり、constは一度宣言・代入したら値の変更は不可能です。一方letで宣言された変数は何度でも値を変更でき、宣言時に代入を行わないといったこともできます。

数値や文字列といった馴染み深い型の他に、真偽値型という値もあります。これは真か偽かを表す値で、条件の成立やフラグ管理などで使用されます。

また、JavaScriptでは文字列の中に値を埋め込むことが可能です。シングルクォートのかわりにバッククォートを使うことで、値の埋め込みを可能にします。

例題

例題:円周率を3.14としたとき、半径(radius)が5の円の面積をコンソールに表示するプログラムを書け。

この問題を解くときに、一番簡単な方法は以下の通りです:

'use strict';

console.log(5 * 5 * 3.14);

これでも、もちろん動作には問題ありません。ですが、これではなんの計算をしているかわかりにくいという問題があります。

より優れたコードを書くためには、変数を用いるといいでしょう:

'use strict';

const pi = 3.14;
const radius = 5;
const area = radius * radius * pi;

console.log(`半径${radius}の円の面積は約${area}です。`);

この例では、出力も工夫し、文字列を使うことでわかりやすくしています。

条件分岐とループ

今までは、プログラムの流れが全く決まってしまっている、一直線なものを作りました。今度は分岐やループを用いて、少し複雑な流れを持つプログラムを作成してみましょう。

if文(条件分岐)

条件によって処理の流れが変化する、いわゆる条件分岐を持つプログラムを作成してみましょう。条件分岐はif文によって実現できます。if文の書式は以下の通りです:

if(真偽値) {
  // 真偽値がtrueの場合はここが実行される
} else {
  // 真偽値がfalseの場合はここが実行される
}

真偽値の部分は、主に比較演算子などを用いた式であることが一般的です。以下のように使います:

'use strict';

// if文による条件分岐
if(3 < 5) {
  console.log('3は5より小さいです!'); // こちらが実行される
} else {
  console.log('3は5より小さくないです!'); // こちらは実行されない
}

console.log('おわりです!');

これを実行すると「3は5より小さいです!」「おわりです!」と出力されます。7行目は実行されません。

現実ではもう少し複雑な式を使います。例えば以下のようにです:

'use strict';

const value = 12;

// %は割り算の余りの計算
// 2で割って余りが0、つまり偶数のとき、という意味
if(value % 2 === 0) {
  console.log(`${value}は偶数です!`);
} else {
  console.log(`${value}は奇数です!`);
}

このときvalueを2で割ってそのあまりが0であるとき、つまり偶数であるとき、ifの中を実行し、そうでない場合elseの中を実行するプログラムになっています。valueの値をいろいろ書き換えて実行してみてください。

elseは省略することもできます。その場合、条件を満たさない場合は何も実行されません:

'use strict';

const score = 50;

console.log(`あなたの点数は${score}点!`);

// 条件を満たした場合のみここが実行される
if(score > 90) {
  console.log('すごい!');
}

console.log('じゃあね。');

また、elseとifを組み合わせて、条件が満たされない場合にさらに条件分岐を行うことが可能です:

'use strict';

const score = 80;

console.log(`あなたの点数は${score}点!`);

// 条件を満たした場合のみここが実行される
// score > 90のときは「すごい!」と表示され、
// それを満たさなかった場合かつscore > 70のときは
// 「わりとすごい!」と表示される。
if(score > 90) {
  console.log('すごい!');
} else if(score > 70) {
  console.log('わりとすごい!')
}

console.log('じゃあね。');

if、else if、else if、else if、elseのように、複数個else ifをぶら下げることも可能です。ただし必ずif → else if → elseの順番でなければなりません。

インデント(字下げ)

ところで気づかれた方もいるかと思いますが、if文の中身、「{」から「}」までの間、行の先頭にスペースが入っています。これはインデント(字下げ)と呼ばれ、コードを見やすくするためのものです。

インデントにプログラム的な意味はありません。ただ単に見栄えを調整するためだけのスペースです。しかし、「この行はこの文の中に存在する」ということが一目でわかると言うことは、コードを書いていく上で非常に重要となってきます。

例えばインデントのない以下のコードを見てください:

'use strict';

const score = 65;

if(score > 60) {
if(score < 70) {
console.log('えらい!');
}
}

これを理解するのはそんなに難しくありませんが、少し時間がかかってしまいます。また、人によっては流れがわからないこともあるでしょう。

このコードにインデントを入れてみます:

'use strict';

const score = 65;

if(score > 60) {
  if(score < 70) {
    console.log('えらい!');
  }
}

if文の中にif文があって、その中にconsole.logがあるということがわかりやすくなりました。

インデントは一般的にスペース2個や4個、タブが使われます。JavaScriptにおいては、多くの場合スペース2個かスペース4個が使用されます。Atomの標準設定ではスペース2個になっているはずです。

インデントにプログラム的な重要性はありません。ですが、わかりやすいということはそれだけ優れたコードであるということです。優れたプログラマは理解しやすいコードを書くものです。

switch文(条件分岐)

例えば変数の値に応じてプログラムの動作モードを切り替えたいとします。if文を使うと以下のようになるでしょう:

'use strict';

const mode = 1;

if(mode === 0) {
  console.log('モード0です!');
} else if(mode === 1) {
  console.log('モード1です!');
} else if(mode === 2) {
  console.log('モード2です!');
} else {
  console.log('無効なモードです');
}

これでも問題ありませんが、少し煩雑です。

そういったときはswitch文を使うと、少し書きやすくなります。switch文の使い方は以下の通りです:

'use strict';

const mode = 1;

switch(mode) {
  case 0:
    console.log('モード0です!');
    break; // switch文を終わる
  case 1:
    console.log('モード1です!');
    break;
  case 2:
    console.log('モード2です!');
    break;
  default: // その他の場合
    console.log('無効なモードです')
}

switch文の中では、caseを使い場合分けをします。今回は数値での場合分けですが、switch文に文字列を渡せば、文字列での場合分けも可能です。if文でのelseにあたるのがdefaultで、どのcaseにも一致しなかった場合に実行されます。

if文と違う点は、break命令によって明示的にswitch文を終了させないといけないことです。たとえばcase 0のときにbreak命令を書き忘れると、その下のcase 1まで実行されてしまいます。この特性はフォールスルーと呼ばれています。

switch文はif文と実現できることが大して変わらない点や、breakを忘れるとフォールスルーが発生してしまうという点もあり、あまり積極的には使われない文です。ですが、全く使わないというわけでもないので、一応覚えておきましょう。

while文(ループ)

プログラムでは、同じ処理を何度も繰り返す、ということがよくあります。そのときに何行も何行も同じ処理を書き続けるのは苦痛ですし、例えば100回繰り返すとして、ミスを発見して修正を加えようとしたら100箇所も書き換えないといけないのです。

そんなことはやってられません。なので、プログラミング言語にはたいていループ(繰り返し)処理を実現するための構文があります。while文はそんなループ処理のうちのひとつです。以下のように使います:

while(真偽値) {
  //trueの間ここを繰り返す
}

書き方はif文と似ていますね。違うのは、真偽値がtrueである間、「{」から「}」までの間のプログラムを繰り返し実行するという点です。

一般的に、while文のループ条件には変数を使い、while文の中で変数の値を書き換えつつ、ループが終わるのを待ちます。変数の値を書き換えていくので、宣言はletで行います。例えば以下のようにです:

'use strict';

let count = 0;

// count < 10の間繰り返す!
while(count < 10) { // ここを「A」とする
  console.log(`今は${count}回目です!`);
  count++; // countを1増やす
} // ここまできたらもう一度「A」まで戻る

これは宣言した変数countが、10未満である間繰り返すというwhile文です。while文の中でcountを増加させており、10回実行したら終わります。

while文には注意点があります。それは真偽値がtrueである間はずっと繰り返されるので、少しのミスで「無限ループ」となり、プログラムが止まらなくなってしまうのです。ブラウザ上で実行するときは無限ループに陥ると、ブラウザが「長い時間がかかっていますが中止しますか?」と尋ねてくるので、中止することでプログラムを停止することができます。

また、以下のコードも無限ループに陥ります(実行しないでください!):

'use strict';

let count = 0;

const cond = count < 10; // この時点で評価されるので、cond = true
while(cond) {
  console.log(`今は${count}回目です!`);
  count++; 
}

これは条件式を変数に代入して実行しようとしています。賢いですが、少し見落としがあります。JavaScriptにおいては、条件式に限らず、式の評価はその場で行われます。つまり、「const cond = count < 10;」は「const cond = 0 < 10;」と評価され、「const cond = true;」と評価されるので、condは常にtrueです。後からcountの数字を書き換えても意味がありません。

while文は途中で抜け出すことも可能です。途中で抜け出すにはbreakを使います:

'use strict';

let count = 0;

while(count < 10) {
  console.log(`今は${count}回目です!`);
  count++;

  // countが5になったら抜け出す
  if(count === 5) {
    break;
  }
}

このコードはcountが5になった段階でbreakしてwhile文を抜け出しています。breakすると無条件で抜け出してしまうので、while文の条件は関係ありません。

また、抜け出すとまではいかなくとも、途中でwhile文の先頭に戻ってループを続けたい場合というのもあります。このときはcontinueを使うことで実現できます。

'use strict';

let count = 0;

while(count < 10) {
  console.log(`今は${count}回目です!`);
  count++;

  continue; // while文の先頭まで戻る

  console.log('ここは実行されない');
}

breakもcontinueもあまり使う機会は多くありませんが、覚えておくと便利です。

for文(ループ)

while文は便利な一方ですぐに無限ループに陥る扱いにくさもありました。そこで、もう少し扱いやすくしたfor文というものもあります。for文は「カウント変数の初期化」「ループの条件」「カウント変数の変化」の3つの部品から構成されています。

'use strict';

// カウント変数の初期化、ループ条件、カウント増加
// の3つをひとまとめに記述できる
for(let count = 0; count < 10; count++) {
  console.log(`今は${count}回目です`);
}

for文の書式は「for(変数の初期化; ループ条件; 変数の変化)」です。

このコードは以下のコードとほぼ同じです:

'use strict';

let count = 0;
while(count < 10) {
  console.log(`今は${count}回目です`);
  count++;
}

また、3つの部品のうちから好きなものを省略することもできます。セミコロンだけは省略できません。例えば「カウント変数の初期化」と「カウント変数の変化」を省略してfor(;count < 10;)と書くとwhile(count <10)と同じになります。全て省略してfor(;;)と書くと無限ループになります。

while文と同じく、breakやcontinueも使えます。

while文とfor文の使い分けというのは、しばしば問題になります。どちらも実現できることは結局同じだからです。使い分けに関しては個人の好み、としか言いようがありませんが、一般的には普通はfor文、特殊なループを行う際にはwhile文、というのが多いように思えます。

例題

例題:0から100までの間の数を順番にコンソールに表示せよ。ただし「0は偶数です」「1は奇数です」などというように、偶数奇数のどちらであるかについても表示せよ。

これはまずはループを使うと0から100まで簡単に繰り返せます。今回はfor文を採用します(もちろんwhile文でも構いません)。まず変数nを0から100まで繰り返すには以下のように書きます:

'use strict';

// n = 0から始まり、ループごとにn++し、
// n <= 100の間繰り返す
for(let n = 0; n <= 100; n++) {
  // ここに処理を書く
}

そして変数nの値が偶数か奇数であるかを、if文を使って条件分岐します。割った余り(%演算子を使う)を見れば偶数かそうでないかの判定ができます。for文の中を書き換えると、以下のようになります:

'use strict';

// n = 0から始まり、ループごとにn++し、
// n <= 100の間繰り返す
for(let n = 0; n <= 100; n++) {
  // 2で割った余りが0なら偶数
  if(n % 2 === 0) {
    console.log(`${n}は偶数です`);
  } else {
    console.log(`${n}は奇数です`);
  }
}

これを実行してみます。

ちゃんと表示されました!100まで表示されていることを確認してください。

変数のスコープ(有効範囲)

今まで話していませんでしたが、実は変数には有効範囲が存在します。この有効範囲のことをスコープと言います。

一般に変数のスコープはブロックの中です。ブロックというのは「{」から「}」までの間のことです。if分やwhile文、for文で見かけた記号ですね。ブロックの中で宣言された変数は、ブロックを抜け出すとアクセスできなくなります。

例えばif文のブロックの中で変数を宣言したとします。このとき、ブロックの外からではその変数にはアクセスできなくなります。以下のコードはエラーになります:

'use strict';

const value = 10;

if(value > 5) {
  const message = `${value}は5より大きい!`;
} // messageのスコープはここまで

console.log(message); // messageにアクセスできない

これを実行すると

「messageは未定義です」とエラーが出ました。このようにして、変数を扱うにはスコープを意識する必要があります。

また、逆に、ブロックの外で宣言された変数は、ブロックの中からアクセスすることが可能です。これは今までの例から見ても明らかでしょう。

難しいのはループにおけるスコープです。ループにおいては、各繰り返しごとにループ内で宣言した変数が無効になります。つまり以下のコードは正常に動作します:

'use strict';

for(let i = 0; i < 10; i++) {
  const sq = i * i;
  console.log(sq);
}

一見すると変数sqの宣言が10回重複しているように見えますが、各繰り返しごとに変数sqが無効になるので、これは正しいプログラムです。

スコープの概念はまだ今回の段階では重要ではありませんが、徐々に重要になってきます。今は完全に理解しなくても良いので、頭の片隅にでも残しておきましょう。

今回のまとめ

今回はJavaScriptの基本的な文法について学びました。値、データ型、変数、どれもプログラミングにおいて大変重要な要素です。これらの要素には、これからずっとお世話になるでしょう。

また、条件武器やループといった、プログラムの流れを制御する構文についても学びました。条件分岐やループを駆使することで、高度なプログラムを組むことができます。

JavaScriptを習得すれば、世界が一気に広がります。ウェブページを動かすこともできますし、ウェブアプリを作ったりもできます。ゲームだって作れます。最近ではJavaScriptでスマートフォンアプリを作ったり、デスクトップアプリが作れるようにもなっています。サーバサイドのプログラムを書くことにも使えます。とにかくなんでもできるようになります。

まだまだ始まったばかりで、なかなか苦戦していると思います。ですが今回学んだ基礎的な部分が一番難しく、後の要素は基礎の応用だけで理解できるようになっているので、頑張ってみてください。

例題

例題1

例題:西暦が与えられたとき、昭和ならば「西暦xxxx年は昭和xx年」、平成ならば「西暦xxxx年は平成xx年」とコンソールに表示するプログラムを作成せよ。ただし与えられる西暦は1930年から2018年までに限るとする。

これの解き方は簡単で、与えられた西暦から平成元年である1989年を引いて、もし0以上なら平成、マイナスなら昭和、と判別することができます。ここでif文を使って場合分けして、それぞれの表示をしましょう。

だいたい以下のようなコードになります:

'use strict';

const syouwaStart = 1926;
const heiseiStart = 1989;

const year = 2017;

// 平成かどうか
const isHeisei = year - heiseiStart >= 0;

// もし平成なら
if(isHeisei) {
  const heiseiYear = year - heiseiStart + 1;
  console.log(`西暦${year}年は平成${heiseiYear}年です。`);
} else { // そうでなければ(=昭和)
  const syouwaYear = year - syouwaStart + 1;
  console.log(`西暦${year}年は昭和${syouwaYear}年です。`);
}

これで適切に表示されるはずです。yearの値を様々に変更して、結果が変わるのを確認してください。

例題2

例題:2の累乗の値を、0乗から5乗までコンソールに表示せよ。なお累乗は「**」で計算できる。

2の0乗、2の1乗、2の2乗…という風に表示していくので、これはforループを使うと楽に解けます。変数を0から5まで変化させて、累乗を計算します:

'use strict';

for(let i = 0; i <= 5; i++) {
  const exp = 2 ** i;
  console.log(`2^${i} = ${exp}`);
}

これを実行すると:

ちゃんと表示されました。

課題

ここから先は課題です。自分の力で解いてみましょう。

課題のjsファイルをmain.jsと混ぜるとあとで管理できなくなるので、別のjsファイルに書きましょう。例えばhomework1-1.jsというjsファイルを作って、そこに書きます。

homework1-1.jsを実行するには、HTMLファイルを書き換えます。以下のように変更します:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JavaScriptでプログラミングを学ぶ</title>
    <script src="homework1-1.js" defer></script>
  </head>

  <body>
  </body>
</html>

変更したのは6行目だけです。jsファイル名の指定部分ですね。これでhomework1-1.jsが実行されます。

課題1(homework1-1.js)

課題:0から23までのいずれかの値である整数hourを考える。このときhourが0から11までのときは「午前xx時です」、12のときは「正午です」、13から23までのときは「午後xx時です」と表示するプログラムを作成せよ。また、hourの値を様々に変えてプログラムが正しく動作していることを確かめよ。

ヒント:ifとif else、elseを使ってうまく場合分けするとよい。

実行例:

  • const hour = 7のとき:「午前7時です」
  • const hour = 12のとき:「正午です」
  • const hour = 20のとき:「午後8時です」

課題2(homework1-2.js)

課題:1から100までの数をコンソールに列挙せよ。ただし3の倍数のときだけは頭が悪くなって数字を出力できないものとする。

ヒント:3の倍数は3で割った時の余りが0となる。

応用課題

ここに書かれているのは応用課題です。無理に解く必要はありません。通常の課題だけでは物足りない人は解いてみてください。

応用課題1(homework1-3.js)

課題:二次方程式ax^2 + bx + c = 0があるとする。ここでa、b、cの値が与えられたとき、xについて実数解を全て出力せよ。

  • ヒント1:判別式detは、det = b * b – 4 * a * c;である。
  • ヒント2:平方根はMath.sqrt命令で求めることができる。例:const sqRoot = Math.sqrt(2);
  • ヒント3:二次方程式の解の公式はx1 = (-b + Math.sqrt(det))/ (2 * a)とx2 = (-b – Math.sqrt(det))/ (2 * a)である。

実行例:

  • a = 1、b = 1、c = -6のとき: 「x = -3」「x = 2」
  • a = 1、b = -10、c = 25のとき:「x = 5」
  • a = 2、b = 1、c = 1のとき:「実数解なし」

応用課題2(homework1-4.js)

課題:ある整数n>2が与えられたとき、nが素数ならば「nは素数です」、素数でないならば「nは素数ではありません」とコンソールに表示するプログラムを作成せよ。

  • ヒント1:素数とは、1と自分自身以外で割り切れない数のことである。
  • ヒント2:素数かどうかを調べるには、nを2からn – 1までの自然数で順番に割っていけばよい。
  • ヒント3:あらかじめletで変数isPrimeをtrueで宣言・代入しておき、一回でも条件を満たさなければfalseを代入すると良い。
'use strict';

const n = 11;

let isPrime = true;
for(let i = 2; i < n; i++) {
  // 条件を満たさない場合、isPrime = false;
}

// 表示する
if(isPrime) {
  console.log(`${n}は素数です`);
} else {
  console.log(`${n}は素数ではありません`);
}

実行例:

  • n = 3のとき:「3は素数です」
  • n = 6のとき:「6は素数ではありません」
  • n = 3331のとき:「3331は素数です」
  • n = 4444のとき:「4444は素数ではありません」

その2:関数へ続く

次の記事 → その2:関数

わからないときは

この連載記事を読んで、わからないところ、不思議なところ、納得のいかないところ等出てくると思います。そのときはTwitterで@kfurumiyaまでご連絡ください。できる範囲で回答いたします。

また、Twitterを使えない、Twitterでは短すぎるという場合はメールアドレス:kotofurumiya@gmail.comまでご連絡ください。

私を信用できないという場合は、以下のプログラミング質問サイトを活用してください:

付録:実数を扱う時の注意点

数学的に考えて、0.1 + 0.2は0.3になります。これをJavaScriptで実行してみます:

'use strict';

if(0.1 + 0.2 === 0.3) {
  console.log('正しい!');
} else {
  console.log('正しくない…');
}

これを実行すると「正しくない…」と表示されてしまいます。いったいどういうことでしょう。この謎の現象を紐解くには、JavaScriptの内部で数値がどう扱われているかを知る必要があります。

コンピュータ内部では、数値は0と1の組み合わせ、いわゆる2進数で扱われます。これはみなさんご存知でしょう。しかし小数点以下の値が存在する「実数」がどう扱われているか、知っている人は多くありません。

実は実数も0と1だけの2進数で表現されています。そしてその表現方法として、ほぼすべてのプログラミング言語では浮動小数点という形式が使われています。浮動小数点では3つの組み合わせで数を表現します。「符号(プラスかマイナスか)」「数」「指数」の3つです。

2進数で実数を表すと、

  • 1.5 → 1.1
  • 3.25 → 11.01

のようになります。ここで0.1が2進数でどうなるかを見てみましょう:

  • 0.1 → 0.0001100110011…

循環小数になりました。循環小数は無限に続く小数で、終わりがありません。しかしコンピュータの内部で数字を表すには、有限桁にする必要があります。具体的にいうと、「符号」「数」「指数」を合わせて64桁(64bit)しかありません。なのでたとえ循環小数でも無理やり64bitに納める必要が出てきます。しかも実際は符号や指数にbitを取られるので、もっと少ない桁(52bit)で表す必要があります。

そうすると絶対に誤差というものが出てきます。必要な情報を切り捨てているわけですからね。なのでコンピュータは「0.1」を正確に表現できないのです。そして計算するごとに誤差は積み上がっていき、最終的に全く違う値になります。

実際に0.1 + 0.2がいくつになるのか確かめてみましょう:

'use strict';

console.log(0.1 + 0.2); // 0.30000000000000004

0.30000000000000004になりました!0.3ではありません!これでは0.3と比較しても同じにならないはずです。

よって、実数を比較する際は、ある程度の誤差を許容する必要があります。===で結ぶのではなく、引き算して絶対値をとって差がdelta(任意の許容誤差)未満であるといったような処理が必要になります。絶対値はMath.abs命令で取ることができます:

'use strict';

const delta = 0.001;
const comp = Math.abs(0.3 - (0.1 + 0.2)) < delta;

console.log(comp);

これで結果がtrueとなりました。

このようにして、実数を扱う時はその誤差に気をつけてください。思わぬバグに繋がる可能性があります。