Program Structure¶
Eloquent JavaScript Chapter 2 の読書ノート。
これまでに見てきた言語要素は自然言語ならば名詞や文の断片に相当する。それらを超えて、意味のある文を表現できるところまで、JavaScript 言語への理解を拡張する。そのようなことを述べている。
なお、C/C++ と Python を十分理解している読者はこの章を流し読みで済ませて良いと思われる。
Expressions and statements¶
値を生成するコードの断片を 式 と呼ぶ。特に、
22
や"psychoanalysis"
のようなリテラル値はすべて式だ。式が文の断片に相当するとすれば、JavaScript における 文 は完全文に相当する。プログラムとは文のリストだ。
最も単純な文はセミコロンが末尾にある式だ。
マシンの内部状態を変化させて、後続の文に影響を与えることもある。このような変化を 副作用 と呼ぶ。
JavaScript では文の最後のセミコロンを省略できる場合がある。セミコロンを安全に省略できる場合のルールはやや複雑で、間違いを犯しやすい。セミコロンの有無の微妙な違いについて理解を深めるまでは、省略しないで書くことを勧める。
Bindings¶
本書では binding という用語が頻出するが、当ノートではそれらを変数に適宜置き換える。
let caught = 5 * 5;
let one = 1, two = 2;
var name = "Ayda";
const greeting = "Hello ";
プログラム中で値を捕捉して保持するために、JavaScript はバインディング、つまり変数と呼ばれるものを用意している。
キーワード
let
は、この文が変数を定義することを示す。いったん変数が定義されると、その名前を式として使うことができる。
既存の変数に対していつでも演算子
=
を使えば、現在の値から切り離して新しい値を指すようにすることができる。空の変数に値を求めると
undefined
という値が返ってくる。単一の
let
文で変数を複数定義することができる。そのような定義は,
で区切らなければならない。キーワード
var
やconst
はlet
と同じような方法で変数を定義する。var
は 2015 年以前の JavaScript で変数が宣言されていた方法だ。紛らわしい特性を持っているため、本書ではほとんど使用しない。const
は C++ のそれと同様の意味があるものの、まったく同じではない。
Binding names¶
変数には、ドル記号
$
やアンダースコア_
を含めることができるが、その他の句読点や特殊文字は使用できない。他のプログラミング言語と同様に、キーワードや予約語と同一の文字列を変数名とすることは許されない。
The environment¶
ある時点で存在する変数とその値の集まりを 環境 と呼ぶ。
プログラムが起動したとき、この環境は空ではない。環境には、言語標準の変数が必ず含まれており、ほとんどの場合、周辺のシステムとのやりとりを行うための変数も含まれる。例えば、ブラウザーならば、現在読み込んでいる Web ページと対話的操作をする機能や、マウスやキーボードの入力を読み取る機能がある。
Functions¶
関数の概念は他のプログラミング言語と同じだ。関数も値の一種と考えることに注意。
関数
prompt
は、最近のウェブプログラミングではあまり使われていない。
The console.log
function¶
最新のウェブブラウザーや Node.js を含むほとんどの JavaScript システムには関数
console.log
が備わっている。この関数は与えられた引数を何らかのテキスト出力デバイスに書き出す。例えばブラウザーならば、その JavaScript コンソールに出力する。
先ほど句読点は変数名として不適格だと述べたが
console.log
はそれに該当しない。これは「変数console
が保持する値からプロパティーlog
を取得する」という式だからだ。
Return values¶
多くの関数が便利なのは、その副作用があるからだ。
関数は値を生成することもあるが、その場合は副作用がなくても役に立つ。
この見解はプログラミング言語に依存するだろう。
Control flow¶
プログラムに複数の文が含まれている場合、それらはあたかも一つの物語のように上から下へと実行される。
関数
Number
は値を数値に変換する。似たような関数にString
やBoolean
があり、これらの型に値を変換する。
Conditional execution¶
他のプログラミング同様、JavaScript でもキーワード if
により条件付き実行を定義する。構文も同じだ。
let num = Number(prompt("Pick a number"));
if (num < 10) {
console.log("Small");
} else if (num < 100) {
console.log("Medium");
} else {
console.log("Large");
}
関数
Number.isNaN
は JavaScript 標準関数であって、与えられた引数がNaN
である場合かつそのときに限りtrue
を返す。関数
Number
は有効な数値を表さない文字列を与えるとNaN
を返す。
while
and do
loops¶
この二つのループも他のプログラミング言語のそれらと同様の仕様だ。
let number = 0;
while (number <= 12) {
console.log(number);
number = number + 2;
}
let yourName;
do {
yourName = prompt("Who are you?");
} while (!yourName);
console.log(yourName);
プログラムを書くということは、何かをより少なくすることであって、より多くすることではない。
Indenting Code¶
ソースコードにおけるインデントの意味は C/C++ のそれと同じようだ。処理系から見ると単なる空白でしかない。
ほとんどのコードエディタープログラムは、新しい行を自動的に適切な量にインデントしてくれる。
for
loops¶
JavaScript や 類似の言語では、前述のループ構文よりも少し短くてより包括的な形式である for
ループを提供している。
for (let number = 0; number <= 12; number = number + 2) {
console.log(number);
}
Breaking Out of a Loop¶
JavaScript では C/C++ と同様の break
文と continue
文がサポートされている。
for (let current = 20; ; current = current + 1) {
if (current % 7 == 0) {
console.log(current);
break;
}
}
Updating bindings succinctly¶
C/C++ と同様に次の演算子も存在する:
+=
-=
++
--
Dispatching on a value with switch¶
C や Java から継承した switch
文もサポートするが、そのぎこちなさもそっくり受け継いでいる。
switch (prompt("What is the weather like?")) {
case "rainy":
console.log("Remember to bring an umbrella.");
break;
case "sunny":
console.log("Dress lightly.");
case "cloudy":
console.log("Go outside.");
break;
default:
console.log("Unknown weather type!");
break;
}
Capitalization¶
標準の JavaScript 関数、そして JavaScript プログラマーのほとんどが、変数の命名を「最初の単語を除くすべての単語を大文字にする」という様式を採用している。
関数がコンストラクターであるならば、その名前は一文字目から大文字とする。
Summary¶
ここまでのノートで代える。
Exercises¶
演習問題の解答をどのように検証したらよいかわからない場合は、Introduction を参照すること。
各問題は、その説明から始まる。この説明を読んでから演習問題を解くこと。解法がわからない場合は巻末のヒントを参照すること。問題の完全な解答はこの本には含まれていないが <https://eloquentjavascript.net/code> で見ることができる。
問題から何かを学びたい場合には、それを解いた後に、あるいは、最低でもその問題を長時間、必死に取り組んだ後に解答を見ることを勧める。
Looping a triangle¶
問題:console.log
を 7 回呼び出して次の三角形を出力するループを書け:
#
##
###
####
#####
######
#######
解答:私の解答を次に記す。ちなみに本書に解答が付いているのかどうかは知らない。以下の演習問題もすべて勝手に解くことにする。
for(let i = 1; i < 8; ++i){
console.log('#'.repeat(i));
}
FizzBuzz¶
問題:console.log
を使って、1 から 100までのすべての数を表示するプログラムを書け。ただし、
3で割り切れる数には、数の代わりに “Fizz” と表示する。
また、3 ではなく 5 で割り切れる数は、”Buzz” と表示する。
これができたら、上のただし以降の挙動を維持したままで、3 と 5 の両方で割り切れる数字を“FizzBuzz” と表示するようにプログラムを変更しろ。
解答:この問題はしばしば目にするのだが、何が面白いのかわからない。前半は:
for(let i = 1; i < 101; ++i){
if(i % 3 == 0){
console.log("Fizz");
}
else if(i % 5 == 0){
console.log("Buzz");
}
else{
console.log(i);
}
}
後半はこれを改造するわけだが、最初の if
ブロックだけを修正すれば十分だ。
for(let i = 1; i < 101; ++i){
if(i % 3 == 0){
if(i % 5 == 0){
console.log("FizzBuzz");
}
else{
console.log("Fizz");
}
}
else if(i % 5 == 0){
console.log("Buzz");
}
else{
console.log(i);
}
}
i % 3 == 0
と i % 5 == 0
は各反復ごとにただ一度ずつ必ず計算するので、
divisible_by_3
のような一時変数を設けてもいいかもしれない。
Chessboard¶
問題:8×8 のグリッドを表す文字列を、改行文字を使って行を区切って作成するプログラムを書け。グリッドの各位置には、スペースまたは記号 #
があり、チェス盤のようになる。
このパターンを生成するプログラムができたら、変数 size = 8
を定義して、任意のサイズで動作するようにプログラムを変更し、与えられた幅と高さのグリッドを出力しろ。
解答:いきなり後半から取り組んでもいいだろう:
const size = 8;
for(let i = 0; i < size; ++i){
if(i % 2 == 0){
console.log(' '.padEnd(size, '# '));
}
else{
console.log('#'.padEnd(size, ' #'));
}
}
以上
Comments¶
C/C++ と同様の方法で、JavaScript コード中にコメントを埋め込むことができる。