ソニックの部屋

主にプログラミングに関する記事を投稿します

JavaScriptまとめ

環境構築

  • warp(ターミナル)のインストール
  • 所定のフォルダで「code .」でvscode起動
  • vscode上でhtmlを作成し「!エンター」で様式入力
  • vscode上で拡張機能のlive serverをインストール
  • vscode上でhtml上で右クリックlive serverで起動
  • scriptタグに記述する
<script src="index.js"></script>
  • scriptタグはbodyの一番下に書く
  • 実務では別jsファイルに分ける
  • 実行結果はブラウザから確認する
  • 実行結果はターミナルから確認する
node index.js

文法

基礎

  • 以下(暗黙的な型変換により)false
undefined;
null;
0;
'';
NaN:
  • 関数は原則モダンなアロー関数を用いて、特に変更するものでもないのでconstを用いる
const hoge = () {
  // 処理
}
  • ウィンドウ全体のオブジェクトはwindow
// ポップアップを出す
window.alert('これはエラーです')
  • ページ全体のオブジェクトはdocument
// buttonタグを取得
document.getElementsByTagName('button')
  • イベントはevent
// buttonを押された時に処理
// addEventListenerは引数を2つ取る
document.getElementsByTagName('button').addEventListener('click', () => {
  // 処理
})
  • HTMLのid属性は一意となるためgetElementByIdを使って確実にデータを取得
// idを取得
// Elementとなりsは付かない
document.getElementById('xx')

// textContentに値を入れると書き換え可能
document.getElementById('xx').textContent = 'りんご'
  • HTMLのオブジェクトをとってくる場合は変数名に$を付けるのが慣習
const $button = document.getElementsByTagName('button')
  • eはイベントを表しe.targetでクリックしたボタンを取得する
const $button = document.getElementsByTagName('button')
$button[0].addEventListener('click', (e) => {
  // $button[0]を表す
  e.target
})
  • 文字列と変数は+で結合可能
  • グルーバル変数を汚染しないために即時関数で書く
(() => {
  // 処理
})()
  • HTML, CSS, JavaScriptを書く際の慣習
    • CSSはclass, JavaScriptはidであてる
    • idには"js-xx"のようにjs-を付ける
    • classやidを使いたくない時はdata-xx(データ属性)を使う
// querySelectorAllで全てのデータを取得
const $content = document.querySelectorAll('[data-content]')

// initで初期化
// style.displayでCSS操作
const init = () => {
  $content[0].style.display = 'block'
}
init()
  • e.preventDefault()でイベントを殺す(リンクに飛ばないなど)
  • e.target.dataset.xxxでデータ属性(data-xxx)の値を取得
  • classList.add('xxx')でクラス属性を全て取得し指定のクラス属性xxxを追加
  • classList.remove('xxx')でクラス属性を全て取得し指定のクラス属性xxxを削除
  • 同じ変数はなるべく一つにまとめる(保守性、パフォーマンスが増す)
  • DOMとはHTML文書内の要素のこと
  • xxx.nextElementSibilingでxxxの次の要素を取得
  • クラスの中の関数はconstなどはいらない
  • クラス内のthisはクラスを参照する
  • クラス内からクラス内のメソッドを呼び出すにはthis.メソッド名とする
  • strict modeで古い文法を排除し厳格かつ安全に実行できる
// 'use strict'という文字列をファイルまたは関数の先頭に書く
'user strict'
// 処理

変数・データ型

  • constは厳密には定数ではなく再代入できない変数
  • 複数行の文字列は``で囲む
`
aaa
bbb
ccc
`
  • 数値から文字列の変換はString()
String(1); // => "1"
  • 文字列から数値の変換はNumber()
// ユーザー入力を文字列として受け取る
const input = window.prompt("数字を入力してください", "42");
// 文字列を数値に変換する
const num = Number(input);
  • プリミティブ値は参照先の値、オブジェクトは参照がコピーされる

関数

  • Rest parametersは、仮引数名の前に...をつけた仮引数のことで、配列となる
function fn(...args) {
    // argsは、渡された引数が入った配列
    console.log(args); // => ["a", "b", "c"]
}
fn("a", "b", "c");
  • Arrow Functionの省略記法
// 関数の仮引数が1つのときは()を省略できる
const fnC = x => {};
// 関数の処理が1つの式である場合に、ブロックとreturn文を省略できる
const mulB = x => x * x;
  • 同じ名前の関数を複数回宣言した場合には、後ろで宣言された関数によって上書きされるため注意
  • 引数として渡される関数のことをコールバック関数
  • コールバック関数を引数として使う関数やメソッドのことを高階関数
function 高階関数(コールバック関数) {
    コールバック関数();
}
// コールバック関数となる無名関数をその場で定義して渡せます。
const array = [1, 2, 3];
array.forEach((value) => {
    console.log(value);
});
  • メソッドを呼び出す場合は、関数呼び出しと同様にオブジェクト.メソッド名()
const obj = {
    method: function() {
        return "this is method";
    }
};

// 短縮記法
const obj = {
    method() {
        return "this is method";
    }
};

console.log(obj.method()); // => "this is method"
  • ブロックで終わる文の末尾には、セミコロンが不要
  • 渡す引数と受け取る引数は引数の順番で決まる(キーワード引数はない)
  • 関数は実行可能なオブジェクト
  • シンボルはプロパティーの重複を避けるために必ず一意の値を返す関数
const s = Symbol();

ループ

  • 配列のforEachメソッド
// 配列の繰り返し処理
const array = [1, 2, 3]
array.forEach(value => {
  console.log(value);
});
  • 配列のsomeメソッド
// 配列の各要素をテストする
function isEven(num) {
    return num % 2 === 0;
}
const numbers = [1, 5, 10, 15, 20];
console.log(numbers.some(isEven)); // => true
  • 配列のfilterメソッド
// 配列から特定の値だけを集めた新しい配列を作る
function isEven(num) {
  return num % 2 === 0;
}
const array = [1, 5, 10, 15, 20]
console.log(array.filter(isEven)); // => [10, 20]
  • for...in文の利用は避け、Object.keysメソッドなどを使って配列として反復処理するなど別の方法を考えたほうがよい
// for...in文は親オブジェクトのプロパティも引き継ぐためObject.keysメソッドを使う
const obj = {
  'a': 1,
  'b': 2,
  'c': 3
};
Object.keys(obj).forEach(key => {
  const value = obj[key];
  console.log(`key:${key}, value:${value}`);
});

// 非推奨
for (const i in obj) {
  console.log(i); // a,b,c
  console.log(obj[i]); // 1,2,3
}
  • 配列の繰り返しにはforEachの他にfor of分も使える
const array = [1, 2, 3];
for (const value of array) {
  console.log(value);
}
  • for文などの構文ではcontinue文やbreak文が利用できるが、配列のメソッドではそれらは利用できない
  • 一方で配列のメソッドは、一時的な変数を管理する必要がないことや、処理をコールバック関数として書くという違いがある
/ object map array set
キー 文字列 指定なし 重複OK 重複NG
for...in o x o x
for...of x o o o
  • mapの使い方
const map = new Map();
const key1 = {};

map.set(key1, 'value1');
console.log(map.get(key1)) // value1
// arry1とarry2は違う配列となる
const arry1 = [1,2,3,4,5];
const arry2 = [...arry1];

// スレッド演算子は引数となる場合はrest parameterという
function sum(...args) {
  let r = 0;
  for(let v of args) {
    r += v;
  }
  return r;
}
const result = sum(1,2,3,4);
console.log(result); // 10

オブジェクト

  • オブジェクトはプロパティの集合であり、プロパティとは名前(キー)と値(バリュー)が対になったもの
  • プロパティへのアクセスは基本的には簡潔なドット記法(.)を使い、ドット記法で書けない場合はブラケット記法([])を使う
const obj = {
  key: value
}
console.log(obj.key)
console.log(obj['key'])

// 削除はdeleteを使う
delete obj.key
  • プロパティを初期化時以外に追加してしまうと、そのオブジェクトがどのようなプロパティを持っているかがわかりにくくなる。 そのため、できる限り作成後に新しいプロパティは追加しないほうがよい
  • プロパティの存在確認にはinを使う
const obj = {
  key: undefined
};
if ('key' in obj) {
//処理
}
  • オブジェクトの列挙方法
const obj = {
    "one": 1,
    "two": 2,
    "three": 3
};
// `Object.keys`はキーを列挙した配列を返す
console.log(Object.keys(obj)); // => ["one", "two", "three"]
// `Object.values`は値を列挙した配列を返す
console.log(Object.values(obj)); // => [1, 2, 3]
// `Object.entries`は[キー, 値]の配列を返す
console.log(Object.entries(obj)); // => [["one", 1], ["two", 2], ["three", 3]]
  • オブジェクトのマージ
    • 空のオブジェクトをtargetにすることで、既存のオブジェクトには影響を与えずマージしたオブジェクトを作ることができる。 そのため、Object.assignメソッドの第一引数には、空のオブジェクトリテラルを指定するのが典型的な利用方法
const objA = {a: 'a'};
const objB = {b: 'b'};
const merged = Object.assign({}, objA, objB);
console.log(merged); // => {a: 'a', b; 'b'}
  • メソッドのthisはオブジェクトを参照する
  • 関数のthisはグルーバルオブジェクトを参照する
  • bindによりthisの参照先を変更することができる(実行しない)
  • call, applyによりthisの参照先を変更することができる(実行する)
  • コンストラクターへの関数の追加はメモリ効率の観点からprototypeを使う→現在はクラスで代替する
// コンストラクターは大文字から始める
function Person(){
  this.name = name;
}

Preson.prototype.hello = function(){
 // 処理 
}

const bob = new Person('Bob', 18);
bob.hello();
if (arg instanceof Array) {
  // 処理
}
class Person {
  constructor(name, age) {
    this._name = name;
    this._age = age;
}

  get name() {
    // 何らかの処理
    return this._name;
}

  set name(val) {
    // 何らかの処理
    this._name = val;
}
}

const p = new Person('Bob', 18);
console.log(p.name) // get経由で呼ばれる
p.name = 'Alice' // set経由で呼ばれる

配列

  • 配列から条件に一致する要素を取得
const colors = [
  {'color': 'red'},
  {'color': 'blue'},
  {'color': 'green'},
  {'color': 'blue'}
]
// 条件に一致する最初の要素を取得
const blueColor = colors.find((obj) => {
  return obj.color === 'blue';
});
console.log(blueColor); // => {'color': 'blue'}
  • 配列から真偽値を取得(配列に含まれているかどうかチェック)
const array = ["Java", "JavaScript", "Ruby"];
// `includes`は含まれているなら`true`を返す
if (array.includes("JavaScript")) {
    console.log("配列にJavaScriptが含まれている");
}
  • 配列の結合
const array = ['A', 'B', 'C'];
const newArray = array.concat(['D', 'E']);
console.log(newArray); // => ['A', 'B', 'C', 'D', 'E']
  • 配列は破壊的な変更かどうか意識する必要がある
破壊的な方法 非破壊な方法
array[index] = item Array.prototype.with
Array.prototype.pop array.slice(0, -1)とarray.at(-1)
Array.prototype.push [...array, item]
Array.prototype.splice Array.prototype.toSpliced
Array.prototype.reverse Array.prototype.toReversed
Array.prototype.sort Array.prototype.toSorted
Array.prototype.shift array.slice(1)とarray.at(0)
Array.prototype.unshift [item, ...array]
Array.prototype.copyWithin なし
Array.prototype.fill なし
  • 破壊的なメソッドは、シンプルだが元の配列も変更してしまうため、意図しない副作用が発生しバグの原因となる可能性あり。 非破壊的なメソッドは、使い分けが必要だが元の配列を変更せずに新しい配列を返すため、副作用が発生することはない。そのため、まず非破壊的な方法で書けるかを検討し、そうではない場合に破壊的な方法を利用するとよい
  • 改めて配列の繰り返し処理
// コールバック関数には要素, インデックス, 配列が引数として渡される
const array = [1, 2, 3];
array.forEach((currentValue, index, array) => {
    console.log(currentValue, index, array);
});
// コンソールの出力
// 1, 0, [1, 2, 3]
// 2, 1, [1, 2, 3]
// 3, 2, [1, 2, 3]
// mapメソッドは配列の要素を順番にコールバック関数へ渡し、コールバック関数が返した値から新しい配列を返す非破壊的なメソッド
const array = [1, 2, 3];
// 各要素に10を乗算した新しい配列を作成する
const newArray = array.map((currentValue, index, array) => {
    return currentValue * 10;
});
console.log(newArray); // => [10, 20, 30]
// 元の配列とは異なるインスタンス
console.log(array === newArray); // => false
// filterメソッドは配列の要素を順番にコールバック関数へ渡し、コールバック関数がtrueを返した要素だけを集めた新しい配列を返す非破壊的なメソッド
const array = [1, 2, 3];
// 奇数の値を持つ要素だけを集めた配列を返す
const newArray = array.filter((currentValue, index, array) => {
    return currentValue % 2 === 1;
});
console.log(newArray); // => [1, 3]
// 元の配列とは異なるインスタンス
console.log(array === newArray); // => false

文字列

  • 正規表現は柔軟で便利だが、コード上から意図が消えてしまいやすい。 そのため、正規表現を扱う際にはコメントや変数名で具体的な意図を補足したほうがよい
  • Stringメソッドで表現できることはStringメソッドで表現し、柔軟性や曖昧な検索が必要な場合はコメントとともに正規表現を利用する
  • 文字列の置換
// 検索対象となる文字列
const str = "???";
// replaceメソッドに文字列を指定した場合は、最初に一致したものだけが置換される
console.log(str.replace("?", "!")); // => "!??"
// replaceAllメソッドに文字列を指定した場合は、一致したものがすべて置換される
console.log(str.replaceAll("?", "!")); // => "!!!"

スコープ

  • 内側から外側のスコープへと順番に変数が定義されているか探す仕組みのことをスコープチェーン
  • クロージャ
    • javascriptは静的スコープ: ある変数がどの値を参照するかは静的に決まる
    • javascriptのメモリ管理の仕組み: 参照されなくなったデータはガベージコレクションにより解放される(反対に参照し続けることで状態を保持する)
    • クロージャーは上記2つの性質を利用して、関数内から特定の変数を参照し続けることで関数が状態を持てる仕組みのこと
    • クロージャーによりプライベート変数を定義できる
  • レキシカルスコープとはコードを書く場所によって参照できる変数が変わるスコープのこと
  • ホイスティングとは変数や関数の定義をコード実行前にメモリに配置すること
  • 即時関数とは宣言と同時に一度だけ実行される関数のこと
    • 即時関数内でしか使えない変数や関数と、即時関数外でも使える変数や関数を定義できる

this

  • thisが実際に使われるのはメソッド
  • 関数の種類
// `function`キーワードからはじめる関数宣言
function fn1() {}
// `function`を式として扱う関数式
const fn2 = function() {};
// Arrow Functionを使った関数式
const fn3 = () => {};
  • JavaScriptではオブジェクトのプロパティが関数である場合にそれをメソッドと呼ぶ
const obj = {
    // `function`キーワードを使ったメソッド
    method1: function() {
    },
    // Arrow Functionを使ったメソッド
    method2: () => {
    }
    // メソッドの短縮記法で定義したメソッド
    method() {
    }
};

// メソッド呼び出し
obj.method();
  • Arrow Function以外におけるthisは「ベースオブジェクト。 ベースオブジェクトとはメソッドを呼ぶ際に、そのメソッドのドット演算子またはブラケット演算子のひとつ左にあるオブジェクトのこと。 ベースオブジェクトがない場合のthisはundefined」
// `fn`関数はメソッドではないのでベースオブジェクトはない
fn();
// `obj.method`メソッドのベースオブジェクトは`obj`
obj.method();
  • Arrow Functionにおけるthisは「自身の外側のスコープにあるもっとも近い関数のthisの値」
function outer() {
    // Arrow Functionで定義した関数を返す
    return () => {
        // この関数の外側には`outer`関数が存在する
        // `outer`関数に`this`を書いた場合と同じ
        return this;
    };
}
// `outer`関数の返り値はArrow Functionにて定義された関数
const innerArrowFunction = outer();
console.log(innerArrowFunction()); // => undefined
  • thisは状況によって異なる値を参照するため注意
  • コンストラクタ関数内でのthisはこれから新しく作るインスタンスオブジェクト
class Point {
  constructor(x, y) {
  this.x = x;
  this.y = y;
  }
}
  • チェーンメソッドをするにはメソッドでthisを返す
class Person {
  hello() {
    // 処理
    return this;
}
  introduce() {
    //処理
}
const bob = new Person()
bob.hello().introduce()  // 繋げて書ける
}

クラス

  • クラス名は大文字ではじめる
  • クラスのメソッド(プロトタイプメソッド)
class クラス {
    メソッド() {
        // このメソッドはプロトタイプメソッドとして定義される
    }
}

// クラスでは次のようにメソッドを定義できない
class クラス {
   // SyntaxError
   メソッド: () => {}
   // SyntaxError
   メソッド: function(){}
}

const a = new クラス()
  • 継承
class 子クラス extends 親クラス {
}
  • コンストラクタの処理順は親クラスから子クラスへ
class Japanese extends Person {
  constructor(name, age, gender) {
    super(name, age);  // 親の変数を呼ぶ
    this.gender = gender;
}
  hello() {
    super.hello();  // 親のメソッドを呼ぶ
    // 処理
}
}
  • クラスはコンストラクタ関数をクラス表記で書けるようにしたもの

例外処理

  • 例外はtry...catch
try {
    console.log("try節:この行は実行されます");
    // 未定義の関数を呼び出してReferenceError例外が発生する
    undefinedFunction();
    // 例外が発生したため、この行は実行されません
} catch (error) {
    // 例外が発生したあとはこのブロックが実行される
    console.log("catch節:この行は実行されます");
    console.log(error instanceof ReferenceError); // => true
    console.log(error.message); // => "undefinedFunction is not defined"
} finally {
    // このブロックは例外の発生に関係なく必ず実行される
    console.log("finally節:この行は実行されます");
}
  • throw文により例外を投げる
try {
    // 例外を投げる
    throw new Error("例外が投げられました");
} catch (error) {
    // catch節のスコープでerrorにアクセスできる
    console.log(error.message); // => "例外が投げられました"
}

非同期処理

  • 同期処理ではコードを順番に処理していき、ひとつの処理が終わるまで次の処理は行わない。 同期処理では実行している処理はひとつだけとなるため、とても直感的な動作となる
  • 非同期処理はコードを順番に処理していくが、ひとつの非同期処理が終わるのを待たずに次の処理を評価する。 つまり、非同期処理では同時に実行している処理が複数ある
  • JavaScriptでは一部の例外を除き非同期処理が並行処理(Concurrent)として扱われる。 並行処理とは、処理を一定の単位ごとに分けて処理を切り替えながら実行すること
  • 並列処理とは、排他的に複数の処理を同時に実行すること
  • Promiseにより非同期処理の状態や結果を表現する
// asyncPromiseTask関数は、Promiseインスタンスを返す
function asyncPromiseTask() {
    return new Promise((resolve, reject) => {
        // さまざまな非同期処理を行う
        // 非同期処理に成功した場合は、resolveを呼ぶ
        // 非同期処理に失敗した場合は、rejectを呼ぶ
    });
}
// asyncPromiseTask関数の非同期処理が成功した時、失敗した時に呼ばれる処理をコールバック関数として登録する
asyncPromiseTask().then(()=> {
    // 非同期処理が成功したときの処理
}).catch(() => {
    // 非同期処理が失敗したときの処理
});
async function doAsync() {
    return "値";
}
// doAsync関数はPromiseを返す
doAsync().then(value => {
    console.log(value); // => "値"
});
  • await式は右辺のPromiseインスタンスがFulfilledまたはRejectedになるまでその場で非同期処理の完了を待つ。 そしてPromiseインスタンスの状態が変わると、次の行の処理を再開する。
  • await式を使うことで非同期処理が同期処理のように上から下へと順番に実行するような処理順で書ける。
async function asyncMain() {
    // PromiseがFulfilledまたはRejectedとなるまで待つ
    await Promiseインスタンス;
    // Promiseインスタンスの状態が変わったら処理を再開する
}
  • キューは実行待ちの行列となり、キューの中でタスクを管理する(非同期処理の実行順を管理)
  • Promiseは簡単に可読性が上がるように非同期処理を書けるにようにしたもの
  • Promiseは非同期のチェーン処理に適した書き方
new Promise(function(resolve, reject) {
  // 同期処理
  resolve('hello');
}).then(function(data) {
  // 非同期処理
  // resolveの時に処理される
}).catch(function(data) {
  // 非同期処理
  // rejectの時に処理される(エラー処理を書く)
}).finally(function() {
  // 非同期処理
  // 終了処理
});
  • async/awaitはPromiseを直感的に記述できるようにしたもの
  • asyncはPromiseを返却する関数宣言を行う
  • awaitはasyncの非同期処理が完了するまで待つ
  • 関数の中でawaitがある場合は必ず非同期処理となりその関数は必ずasyncを付ける
async function init() {
  let val = await sleep(0);
  val = await sleep(val);
  val = await sleep(val);
  val = await sleep(val);
}

その他

  • Mapはキーと値の組み合わせからなるコレクションを扱うビルトインオブジェクト
// 定義
const map = new Map();
const map = new Map([["key1", "value1"], ["key2", "value2"]]);
// 新しい要素の追加
map.set("key", "value1");
// キーの存在確認
console.log(map.has("key")); // => true
// 反復処理
const results = [];
map.forEach((value, key) => {
    results.push(`${key}:${value}`);
});
console.log(results); // => ["key1:value1","key2:value2"]
  • Setは重複する値がないことを保証した順序を持たないコレクションを扱うビルトインオブジェクト
  • JSONは文字列
  • JSONをオブジェクトに変換する
// JSONはダブルクォートのみを許容する
const json = '{ "id": 1, "name": "js-primer" }';
const obj = JSON.parse(json);
console.log(obj.id); // => 1
console.log(obj.name); // => "js-primer"
  • オブジェクトをJSONに変換する
const obj = { id: 1, name: "js-primer", bio: null };
console.log(JSON.stringify(obj)); // => '{"id":1,"name":"js-primer","bio":null}'
実行
  • 時刻値を取得する
// 現在の時刻を表すインスタンスを作成する
const now = new Date();
// 時刻値を取得する
console.log(now.getTime());
  • ただし、JavaScriptにおける日付・時刻の処理は、標準のDateではなくライブラリを使うことが一般的
  • 乱数を生成する
for (let i=0; i < 5; i++) {
    // 毎回ランダムな浮動小数点数を返す
    console.log(Math.random());
}
// 名前つきエクスポートされたfooとbarをインポートする
import { foo, bar } from "./my-module.js";
console.log(foo); // => "foo"
console.log(bar); // => function bar()

アプリ作成時の気付き

  • エントリーポイントとは、アプリケーションの中で一番最初に呼び出される部分のこと
  • Fetch APIはHTTP通信を行ってリソースを取得するためのAPI
  • fetch
    • Promiseを返す
    • thenメソッドが使える(Promiseを返すから)
    • jsonメソッドが使える
// HTTPリクエスト
const userId = "任意のGitHubユーザーID";
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`);
// HTTPレスポンス
const userId = "js-primer-example";
fetch(`https://api.github.com/users/${encodeURIComponent(userId)}`)
    .then(response => {
        console.log(response.status); // => 200
        return response.json().then(userInfo => {
            // JSONパースされたオブジェクトが渡される
            console.log(userInfo); // => {...}
        });
    });
// commanderモジュールからprogramオブジェクトをインポートする
import { program } from "commander";

// コマンドライン引数をcommanderでパースする
program.parse(process.argv);

// ファイルパスをprogram.args配列から取り出す
const filePath = program.args[0];
  • Node.jsでファイルの読み書きを行うには、標準モジュールのfsモジュールを使う
  • Node.jsの標準モジュールはnode:fsのようにnode:プリフィックスをつけてインポートできる。 プリフィックスを付けないfsでもインポートできるが、npmからインストールしたサードパーティ製のモジュールとの区別が明確になるため、付けておくことが推奨
// fs/promisesモジュール全体を読み込む
import * as fs from "node:fs/promises";

// fs/promisesモジュールからreadFile関数を読み込む
import { readFile } from "node:fs/promises";
  • ファイルの読み書きは存在の有無や権限、ファイルシステムの違いなどによって例外が発生しやすいので、必ずエラーハンドリング処理を書く
  • markedパッケージを使ってMarkdown文字列をHTML文字列に変換可能
  • テスティングフレームワークのmochaパッケージをインストールし、npm testコマンドでmochaコマンドを実行することによりテストが可能
$ npm test
> mocha test/
  • event.preventDefaultメソッドは、submitイベントの発生元であるフォームが持つデフォルトの動作をキャンセルする
    • フォームが持つデフォルトの動作とは、フォームの内容を指定したURLへ送信するという動作
    • form要素に送信先が指定されていないため、現在のURLに対してフォームの内容を送信
    • 現在のURLに対してフォームの送信が行われると、結果的にページがリロードされる
    • リロードさせないためにevent.preventDefaultメソッドを使う
formElement.addEventListener("submit", (event) => {
    // submitイベントの本来の動作を止める
    event.preventDefault();
    console.log(`入力欄の値: ${inputElement.value}`);
});
  • イベントが発生したことを元に処理を進める方法をイベント駆動(イベントドリブン)
  • commanderでコマンドライン引数にオプションを付ける
// コマンドライン引数の取得とオプションの設定
import {program} from 'commander';
program.option('-m, --month <number>');
program.parse(process.argv);
const options = program.opts();
console.log(options.month;);
  • 異常終了(0は正常終了)
process.exit(1);
  • 改行せずに表示
process.stdout.write('xxx');
  • 数字の二桁表示
// iは数字
i = i.toString().padStart(2, '0');
  • 複数の空白の作り方
// 空白数を返す
let fn_blank = (num) => {
  return '   '.repeat(num);
}
  • Webブラウザでモジュールを使用するためには、scriptタグにtype="module"属性を追加
<body>
  <h1>ToDo List</h1>
  <script type="module" src="./index.js"></script>
</body>
  • プライベートフィールドは#を付ける
// TodoListModelはAppクラスの外からは触る必要がないためプライベートフィールドとする
export class App {
  #todoListModel = new TodoListModel();
}
  • confirmで削除前のメッセージを表示させる
// OKならtrue、キャンセルならfalseを返す
let result = confirm('削除OK?')

参考文献
happiness-chain教材
JavaScript入門・完全版コース/プログラミング初心者向け、コスパ最強講座
JavaScript Primer
Commander.jsを使用してNode.jsのCLI引数を処理する
Node.jsで終了ステータスコードを使うなら押さえておきたいasyncと終了ステータスコードの話
Node.jsでコンソールの表示を上書きする
【JavaScript】padStartメソッドで0詰め2桁の数字を作る関数
JSのプライベートフィールドは接頭辞に#(シャープ)を付けて表示する
JavaScriptによる削除する前に確認メッセージ
CodeMafia, 2024, 「【JS】ガチで学びたい人のためのJavaScriptカニズム」, udemy, (2024/4/16取得,https://www.udemy.com/).