「なぜこの本を書いたのか」から引用する。
Java や、それに似た言語を知っていて、 JavaScript をいまの姿で(歴史的な残滓を除いた形で)学びたいと思っているプログラマは何百万人もいるだろうに、そういう人たちのための本を見つけることができないのは、おかしなことではないか。
だから、私がこの本を書くことになった。
まえがきにある、5 つの大原則は大事だと思う。以下引用する。
- 変数は、
varでなく、letまたはconstで宣言せよ。- strict モードを使え。
- 型を理解し、自動的な型変換を避けよ。
- プロトタイプを理解しよう。しかし、クラスとコンストラクタとメソッドには現在の構文を使おう。
thisは、コンストラクタまたはメソッドの中でだけ使おう。
私は頭が悪いので、本書を読み進めるのが難しかった。
各章の末尾には演習問題がある。第4章「オブジェクト指向プログラミング」の演習問題の 8 番 (p.109) をやってみた。
8 抽象クラスの古典的な例が、ツリー(木構造)のノードである。 ノードには、子供のある親ノードと子供のない葉ノードの2種類がある(コードブロックの引用は割愛)。 Java や C++ では、このようにツリーノードをモデリングするだろう。けれどお JavaScript では、
n.depth()を呼び出せるようにするのに、抽象クラスは必要ない。継承なしでクラスを書き直し、 テストプログラムも作ろう。
書き直してみてテストプログラムも作ったが、果たしてこれでいいのだろうか。
コード
/* Cay S. Horstmann : JavaScript モダンプログラミング完全ガイド */
/* p.109 ekz08.js */
"use strict";
class Node {
constructor(value, children) {
this.value = value;
this.children = children;
}
depth() {
return this.children === undefined
? 1
: 1 + Math.max(...this.children.map((n) => n.depth()));
}
}
const tarao = new Node("Tarao");
const sazae = new Node("Sazae", [tarao]);
const katuo = new Node("Katuo");
const wakame = new Node("Wakame");
const fune = new Node("Fune", [sazae, katuo, wakame]);
console.log(`tarao : ${tarao.depth()}`);
console.log(`sazae : ${sazae.depth()}`);
console.log(`katuo : ${katuo.depth()}`);
console.log(`wakame : ${wakame.depth()}`);
console.log(`fune : ${fune.depth()}`);
実行結果
PS C:> node .\ekz08.js tarao : 1 sazae : 2 katuo : 1 wakame : 1 fune : 3
本書の記述や例を参考にしたページを作った。正規表現とパターンマッチングなど。
久しぶりに本書を読み返した。第5章「数と日付/時刻」の演習問題の 11 番 (p.127) をやってみた。
11 ある年が「うるう年」()かどうかを判定する関数を、2 種類の異なる実装で書こう。
ここで、所与の年は西暦 y であるとする。方針はいくつか考えられる。
第1の方針であれば、次のようになるだろうか。
function isLeapYear(y) {
if (y % 400 === 0) {
return true
} else if (y % 100 === 0) {
return false
} else if (y % 4 === 0) {
return true
} else {
return false
}
}
第2の方針であれば、次のようになるだろうか。
function isLeapYear(y) {
const before = new Date(y + 1, 0)
const after = new Date(y, 0)
return (before - after) / 86400000 === 365 ? true : false
}
この第2の方針の実装には、本書 p.122 のコラムにある第2の注意を参考にした。
注意:Date オブジェクトを算術演算の式に遣うと、上記の「注意」と同じフォーマットの文字列か、エポックからのミリ秒数への、自動的な変換が行なわれる。
(中略)これが有益なのは、2つの時刻の差を計算するときだけだ。
第3の方針の実装は最初やめるつもりでいた。2 種類の異なる実装で書こう
とあったからだ。しかし、面白いので、書いてみた。
function isLeapYear(y) {
return (new Date(y, 2, 0).getDate() === 29) ? true : false
}
この実装には、本書 p.123 の注意を参考にした。
注意:もし zeroBasedMonth、day、hours などに範囲外の値を提供すると、日付時刻は黙って調整される。たとえば、new Date(2019, 13, -2) は 2020 年 1 月 29 日になる。
この黙って調整される
という箇所の調整の具体的な内容が、例だけではわかりにくかったので、https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/Date を見てみると、次のように説明されていた。
いずれかの引数が定義された境界を超えた場合、「繰り上げ」が行われます。例えば、 monthIndex に 11 よりも大きな値が渡された場合、その月は年を増加させます。
minutes に 59 よりも大きな値が渡された場合、hours
はそれに応じて増加します。したがって、 new Date(1990, 12, 1) は 1991 年 1 月 1 日を返し、 new Date(2020, 5, 19, 25, 65) は 2020 年 6 月 20 日の午前 2 時 5 分を返します。
同様に、何か引数がアンダーフローする場合は、上位の引数を「桁借り」します。例えば、new Date(2020, 5, 0) は、 2020 年 5 月 31 日を返します。
この伝でいくと、new Date(y, 2, 0) が y 年 3 月 1 日の 1 日前、すなわち y 年 2 月 28 日か 29 日かを表すことがわかる。そこで getDate() メソッドを使って、29 か否かを判定すればうるう年か否かがわかることになる。
(この項、2025-11-04)
リンク
- @sobacha 氏によるJavaScriptモダンプログラミング完全ガイドの演習問題の解答(github.com)
- hiro21 氏によるJavaScriptモダンプログラミング完全ガイドの演習問題の解答(github.com)
(この項、2025-11-04)
書誌情報
書名 JavaScript モダンプログラミング完全ガイド
著者 Cay S. Horstmann
訳者 吉川邦夫
発行日 2020 年 12 月 21 日 初版第1刷
発行元 インプレス
定価 3000 円(本体)
サイズ A5 判変形 ページ
ISBN 978-4-295-01056-2
その他 越谷市立図書館で借りて読む
まりんきょ学問所 >
コンピュータについて >
コンピュータの本 >
JavaScript, altJS > Cay S.
Horstmann:JavaScript モダンプログラミング完全ガイド
MARUYAMA Satosi