我的网页
欢迎光临
- 项目1
- 项目2
はじめに
あなたはすでに HTML と CSS を学び、見栄えの良い Web ページを作れるようになりました。しかし、「ボタンをクリックしても反応がない」「フォームを入力しても送信できない」といったことに気づくかもしれません。Web ページはまるで「静的な」画像のようです。
これが JavaScript が必要な理由です——JavaScript は Web ページに「命」を吹き込みます。ボタンをクリックするとメニューが表示され、テキストを入力するとリアルタイム検索ができ、スクロールするとさらにコンテンツが読み込まれます……これらのインタラクティブな効果はすべて JavaScript によって実現されています。
vibecoding では、AI がコードの大部分を書いてくれます。しかし、少なくともコードが何をしているのかを理解できる必要があります。さもなければ、AI が間違ったコードを書いても気づけません。この記事を読めば、次のことができるようになります:
この記事で学ぶこと:
| 章 | 内容 | 学んだ後にできること |
|---|---|---|
| 第 1 章 | JavaScript とは | Web ページでどのような役割を果たすかを理解する |
| 第 2 章 | データと変数 | プログラムがどのようにデータを保存し、使用するかを知る |
| 第 3 章 | 関数とロジック | コードの条件分岐、ループ、再利用のロジックを理解する |
| 第 4 章 | DOM とイベント | コードがどのように Web ページを制御し、ユーザー操作に応答するかを知る |
| 第 5 章 | 実践テクニック | AI コードの読み方、エラー遭遇時の伝え方 |
各章は「コードを識別できる」ことから始まります。手書きできる必要はありません。わからないコードがあれば、いつでもここに戻って確認してください。
🤔 核心的な問い
なぜ Web ページに JavaScript が必要なのか? HTML と CSS だけで Web ページにコンテンツとスタイルを持たせられるのに、なぜ新しい言語を学ぶ必要があるのか?
📄 JavaScript がない Web ページ
まるで紙のポスター、見るだけ
🚀 JavaScript がある Web ページ
まるで本物のアプリケーション
三者関係を一文で理解する:
| 技術 | 比喩 | 役割 |
|---|---|---|
| HTML | 骨格 | Web ページの構造とコンテンツを定義 |
| CSS | 皮膚 | Web ページの外観とスタイルを定義 |
| JavaScript | 筋肉と神経系 | Web ページに応答性、インタラクション、思考能力を与える |
JavaScript を学び始めた開発者のつまずき
JavaScript を学び始めたばかりの開発者が AI で「カウンター」アプリを作りました:ボタンをクリックすると数字が 1 増えます。AI が生成したコードは正常に動作しました。
しかし彼は「クリックで 2 増やす」に変更したくなり、AI に「毎回のクリックで 2 増やして」と伝えました。AI はコードを修正しましたが、数字はまだ 1 しか増えません。
彼は AI に「なぜ効果がないのか」と尋ね、AI は説明しましたが、コード内の count = count + 1 が何を意味するのか理解できず、AI がその箇所を修正したのかどうかもわかりませんでした。「2 増えない」と繰り返すしかなく、AI は何度も修正しましたが、ある時は初期値を 2 に変え、ある時は全く関係ない場所に 2 を足しました。
最終的に彼は第 2 章の「変数」の概念を読んで、count = count + 1 が count の値に 1 を足して再び保存していることを理解しました。そして AI に「count + 1 を count + 2 に変更して」と伝えました。
一度で修正できました。
これが JavaScript を理解すべき理由です——手書きするためではなく、AI が正しく修正しなかったときに、問題の箇所を一目で見抜き、一言で的確に指摘できるようにするためです。
深く学ぶ前に、AI が生成した実際のコードを見てみましょう。理解できなくても心配しないでください。印象だけ持ってもらえれば、後で各部分を一つずつ解説します。
シナリオ:「ボタンをクリックして背景色を切り替える」機能を作る
// 色のセットを定義
const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4']
let currentIndex = 0
// ページ上のボタンを見つける
const button = document.querySelector('#changeBtn')
// ボタンにクリックイベントを追加
button.addEventListener('click', () => {
currentIndex = (currentIndex + 1) % colors.length
document.body.style.backgroundColor = colors[currentIndex]
})このコードは何をしているのか?
| コード | 役割 | 対応する章 |
|---|---|---|
const colors = [...] | 色データのセットを定義 | 第 2 章:配列 |
let currentIndex = 0 | 現在表示している色の番号を記録 | 第 2 章:変数 |
document.querySelector(...) | ページ上のボタンを見つける | 第 4 章:DOM 検索 |
button.addEventListener(...) | ボタンにクリックイベントを追加 | 第 4 章:イベントリスニング |
() => {...} | クリック後に実行するコードを定義 | 第 3 章:アロー関数 |
💡 核心的な示唆
今すぐすべてのコード行を理解する必要はありません。ただ覚えておいてください:JavaScript コードとは一連の命令であり、「ユーザーが何かをしたとき、何が起こるべきか」をブラウザに伝えるものです。
🤔 核心的な問い
プログラムはどのようにして物事を「記憶」するのか? ユーザーの入力内容、サーバーから取得したデータ、計算途中の中間結果——これらの情報はどこに保存されているのか?
変数はラベル付きの箱のようなもの——データを中に入れて、後でラベルを通じて取り出すことができます。
const name = "田中" // 名前は変わらないので const
let age = 25 // 年齢は変わる可能性があるので letなぜ const と let を区別するのか?
想像してみてください:あなたのマイナンバー(const)は生涯変わりませんが、年齢(let)は毎年変わります。JavaScript では、異なるキーワードを使ってこの「変わるものと変わらないもの」の意図を表現します。
| キーワード | 変更可否 | 使用シーン | 例 |
|---|---|---|---|
const | ❌ 不可 | 値が変わらないデータ | マイナンバー、設定項目、色リスト |
let | ✅ 可 | 値が変わるデータ | カウンター、現在選択中のオプション、ユーザー入力 |
// const を使用:これらの値は変わらない
const PI = 3.14159
const MAX_USERS = 100
const APP_NAME = "TodoList"
// let を使用:これらの値は変化する
let count = 0
count = 1 // ✅ 変更可能
count = count + 1 // ✅ 元の値に基づいて計算可能
// const を使うとどうなる?
const fixedCount = 0
fixedCount = 1 // ❌ エラー!const は再代入できない👇 実際に試してみよう:以下のコードを修正して、const と let の違いを観察してください
const name = "张三"let age = 25JavaScript はデータをいくつかの型に分類します。最もよく使われるのは次の 3 つです:
| 型 | 説明 | 例 | 実際のシーン |
|---|---|---|---|
string(文字列) | テキストコンテンツ | "hello", 'こんにちは' | ユーザー名、商品説明、メッセージ |
number(数値) | 数値 | 42, 3.14 | 価格、数量、評価 |
boolean(真偽値) | はい/いいえ | true, false | ログイン済みか、完了したか、表示可能か |
知っておくべき 2 つの特殊な値:
undefined → 変数は宣言されたが、まだ値が代入されていないnull → 意図的に空に設定(「ここには値がない」ことを示す)AI コードでは、バッククォート(`)で囲まれ、中に ${...} を含む文字列をよく見かけます:
const name = "田中"
const age = 25
// 従来の書き方(面倒)
const message = "私は" + name + "、今年" + age + "歳です"
// テンプレート文字列(簡潔)
const message = `私は${name}、今年${age}歳です`
// 結果:"私は田中、今年25歳です"識別のポイント:バッククォートと ${} を見たら、変数をテキストに埋め込んでいるのだとわかります。
オブジェクト = 名前付きプロパティのセット(個人情報表のようなもの)
const user = {
name: "田中",
age: 25,
isVIP: true
}
// ドット記法でプロパティにアクセス
console.log(user.name) // "田中"
console.log(user.age) // 25配列 = 順序付きデータのセット(リストのようなもの)
const colors = ['赤', '緑', '青']
// インデックスでアクセス(0 から始まる)
console.log(colors[0]) // "赤"
console.log(colors[1]) // "緑"ネスト構造:オブジェクトの中に配列、配列の中にオブジェクト
これは AI コードで最も一般的なデータ構造です:
const todos = [
{ id: 1, text: "JavaScript を学ぶ", done: false },
{ id: 2, text: "プロジェクトを作る", done: true },
{ id: 3, text: "ドキュメントを書く", done: false }
]
// アクセス:まず配列の 0 番目を取り、その text プロパティを取得
console.log(todos[0].text) // "JavaScript を学ぶ"💡 識別のコツ
{} を見たら → これはオブジェクト、中身は 名前: 値 のセット[] を見たら → これは配列、中身は順序付けられた値のセットdata[0].name を見たら → まず配列の 0 番目を取り、その name プロパティを取得これは初心者が最もよく遭遇する問題の一つです!
基本型(string、number、boolean)の代入 = まったく新しいデータのコピー:
let a = 10
let b = a // b は a のコピーを取得
b = 20
console.log(a) // 10(a は影響を受けない)オブジェクトと配列の代入 = 「アドレス」をコピー(同じものを指す):
let user1 = { name: "田中" }
let user2 = user1 // user2 は同じオブジェクトを指す
user2.name = "佐藤" // user2 の変更が user1 に影響する
console.log(user1.name) // "佐藤"(user1 も変わった!)なぜコピーを作成するのか?
React/Vue では、データを直接変更すると画面が更新されません。そのため AI コードではよく [...array] や {...obj} を見かけます——これはコピーを作成し、相互影響を防いでいます。
// スプレッド演算子でコピーを作成
const arr1 = [1, 2, 3]
const arr2 = [...arr1] // 新しい配列を作成
arr2.push(4)
console.log(arr1) // [1, 2, 3](影響を受けない)
console.log(arr2) // [1, 2, 3, 4]👇 実際に試してみよう:コピーを変更したときの元データの変化を観察してください
let a = 10
let b = a // b=10
b = 20 // a还是10let obj1 = {age:25}
let obj2 = obj1
obj2.age=30 // obj1也变了!
// 用 {...obj1} 复制この 2 つの構文は AI コードのあちこちに登場します。知らないとコードが読めません。
分割代入:オブジェクトや配列からデータを素早く抽出
const user = { name: "田中", age: 25, city: "東京" }
// 従来の書き方(面倒)
const name = user.name
const age = user.age
// 分割代入の書き方(簡潔)
const { name, age } = user
// 効果は同じだが、一行で完了スプレッド演算子:コピーしてデータを拡張
// 配列をコピーして新しい要素を追加
const arr1 = [1, 2, 3]
const arr2 = [...arr1, 4, 5] // [1, 2, 3, 4, 5]
// オブジェクトをコピーして新しいプロパティを追加
const user1 = { name: "田中", age: 25 }
const user2 = { ...user1, city: "東京" }
// { name: "田中", age: 25, city: "東京" }💡 識別のコツ
const { name, age } = person を見たら → person オブジェクトから name と age を抽出...array や ...obj を見たら → 配列やオブジェクトを展開して平らにしている🤔 核心的な問い
コードはどのように「判断」し「繰り返し処理」をするのか? プログラムは条件に応じて異なる操作を実行し、特定のタスクを繰り返し実行する必要があります——これらのロジックはどのように表現するのか?
if/else:最も基本的な条件分岐
const age = 18
if (age >= 18) {
console.log("成人")
} else {
console.log("未成年")
}三項演算子:if/else の省略形
// 完全な書き方(4 行)
let message
if (age >= 18) {
message = "成人"
} else {
message = "未成年"
}
// 三項演算子(1 行)
const message = age >= 18 ? "成人" : "未成年"
// 形式:条件 ? 条件が真の場合の値 : 条件が偽の場合の値&& 短絡評価:React コードでよく見かける
// isLoggedIn が true の場合のみユーザーパネルを表示
isLoggedIn && <UserPanel />
// 以下と同等
if (isLoggedIn) {
return <UserPanel />
}💡 識別のコツ
? : を見たら → これは三項演算子、if/else の省略形&& を見たら → 前が true の場合のみ後ろを実行関数 = 料理のレシピ
// 関数を定義(レシピを書き留める)
function greet(name) {
return "Hello " + name
}
// 関数を呼び出す(レシピ通りに料理を作る)
console.log(greet("田中")) // "Hello 田中"
console.log(greet("佐藤")) // "Hello 佐藤"3 つの書き方、一目で識別:
// 1. function 宣言(従来の書き方)
function greet(name) {
return "Hello " + name
}
// 2. アロー関数(AI コードで最もよく使われる)
const greet = (name) => {
return "Hello " + name
}
// 3. アロー関数の省略形(1 行のみの場合)
const greet = (name) => "Hello " + name👇 実際に試してみよう:異なる名前を入力して、関数がどのように動作するか観察してください
price * discountconst calculatePrice = (price, discount) => {
return price * discount
}
// 或者更简洁:
const calculatePrice = (price, discount) => price * discount💡 識別のコツ
function または => を見たら → これは関数fn() を見たら → この関数を呼び出している() => {} を見たら → アロー関数、モダン JS の主流の書き方React/Vue では、ほぼすべてのリストレンダリングでこれらのメソッドが使われます。
const todos = [
{ id: 1, text: "学習", done: false },
{ id: 2, text: "仕事", done: true }
]
// .map():配列の各要素を別のものに変換
const texts = todos.map(todo => todo.text)
// ["学習", "仕事"]
// .filter():条件に合う要素をフィルタリング
const unfinished = todos.filter(todo => !todo.done)
// [{ id: 1, text: "学習", done: false }]
// .find():条件に合う最初の要素を見つける
const found = todos.find(todo => todo.id === 1)
// { id: 1, text: "学習", done: false }💡 識別のコツ
.map() を見たら → 配列を変換し、新しい配列を返す.filter() を見たら → 配列をフィルタリングitems.map(item => <li>{item.name}</li>) を見たら → 各データ項目をリストタグに変換「部屋」の比喩で:
const global = "グローバル変数" // 廊下にある物
function room() {
const local = "部屋の中の物" // 部屋の中の物
console.log(global) // ✅ 廊下が見える
}
console.log(local) // ❌ エラー!外からは部屋の中の物が見えない核心的な直感: コードがどこに書かれているかが、どの変数を見られるかを決定します。
👇 実際に試してみよう:異なるスコープをクリックして、どの変数にアクセスできるか観察してください
const appName = "Todo" // 全局作用域
function greet() {
const message = "你好" // 函数作用域
if (true) {
const greeting = message + appName // 块级作用域
console.log(greeting)
}
console.log(greeting) // ❌ 报错!外层看不到内层
}独立した概念としてではなく、具体的なシーンから理解しましょう:
function setupCounter() {
let count = 0 // この変数は関数の内部にある
return {
add: () => { count++; return count },
getCount: () => count
}
}
const counter = setupCounter()
console.log(counter.add()) // 1
console.log(counter.add()) // 2
console.log(counter.getCount()) // 2核心的な直感: 関数は作成されるときに、周囲の変数を「記憶」します。外側の関数の実行が終了しても、その記憶は保持されます。
👇 実際に試してみよう:クロージャがどのように関数に状態を「記憶」させるか観察してください
複雑なバインディングルールではなく、最も一般的なシーンだけを説明します:
シーン 1:オブジェクトのメソッド内では、this はそのオブジェクトを指す
const user = {
name: "田中",
sayHi() {
console.log("こんにちは、私は" + this.name) // this は user を指す
}
}
user.sayHi() // "こんにちは、私は田中"シーン 2:イベントリスナー内では、this はイベントを発生させた要素を指す
button.addEventListener('click', function() {
console.log(this) // this は button 要素を指す
})
// ただしアロー関数は this を変更しない
button.addEventListener('click', () => {
console.log(this) // this は外側の this を指す
})💡 問題が起きたら?
AI コードに this 関連のバグが出た場合(例:Cannot read property of undefined)、AI にこう伝えてください:「このメソッドの this の参照先が正しくありません。アロー関数に変更するか、bind を使ってください」
🤔 核心的な問い
JavaScript はどのように Web ページと「対話」するのか? ページ上の要素をどうやって見つけるのか? ユーザーのクリックや入力にどう応答するのか? サーバーからどうやってデータを取得するのか?
Web ページは JavaScript の目には「木」として映り、各 HTML タグは木の上の「ノード」です。
<html>
<body>
<h1>タイトル</h1>
<p>段落</p>
<ul>
<li>項目1</li>
<li>項目2</li>
</ul>
</body>
</html>JS で Web ページを操作 = ノードを見つける + ノードを変更する + ノードを作成/削除する
👇 実際に試してみよう:ノードをクリックして、DOM ツリーがどのように構成されているか観察してください
欢迎光临
点击上方按钮查看对应代码要素の検索:
// CSS セレクタで検索(最も一般的)
const title = document.querySelector('h1') // 最初の h1 を探す
const button = document.querySelector('#btn') // id="btn" の要素を探す
const items = document.querySelectorAll('.item') // class="item" の全要素を探す要素の変更:
// テキストを変更
title.textContent = "新しいタイトル"
// スタイルを変更
element.style.color = "red"
element.style.fontSize = "20px"
// CSS クラスを変更
element.classList.add('active') // クラスを追加
element.classList.remove('hidden') // クラスを削除
element.classList.toggle('open') // クラスを切り替え(あれば削除、なければ追加)💡 識別のコツ
document.querySelector を見たら → Web ページの要素を検索している.textContent を見たら → テキストを変更.style.xxx を見たら → スタイルを変更.classList.add/remove/toggle を見たら → CSS クラスを変更addEventListener:要素にイベントリスナーを追加
button.addEventListener('click', () => {
console.log("ボタンがクリックされました")
})一般的なイベント:
| イベント | 発生タイミング | 実際のシーン |
|---|---|---|
click | クリック | ボタンクリック、リンク遷移 |
input | 入力欄の内容が変化 | リアルタイム検索、フォームバリデーション |
submit | フォーム送信 | ログイン、登録、データ送信 |
scroll | ページスクロール | 遅延読み込み、トップに戻る |
イベントオブジェクト:より多くの情報を取得
input.addEventListener('input', (e) => {
console.log(e.target.value) // 入力欄の値を取得
e.preventDefault() // デフォルト動作を防止(例:フォーム送信後のページリフレッシュ)
})💡 実践への応用
ボタンに機能を追加したいとき、本質的には AI にこう伝えることです:「このボタンにクリックイベントを追加して、クリックされたら特定の操作を実行してください」
レストランの比喩:
注文した後、キッチンの前で待つ必要はありません。先に他のことをして、料理ができたらウェイターが運んできてくれます。
最も一般的なシーン:サーバーからデータを取得
// 同期の書き方(ページが固まるので使わないで)
const data = fetch('/api/data') // ❌ この書き方では固まる
// 非同期の書き方(正しい)
async function loadData() {
try {
const response = await fetch('/api/data')
const data = await response.json()
console.log(data)
} catch (error) {
console.error('エラーが発生しました:', error)
}
}async/await 構文:
async → この関数内に非同期操作があることをマークawait → この操作の完了を待つ(ただしページは固まらない)try/catch → 発生する可能性のあるエラーを処理👇 実際に試してみよう:非同期操作の実行順序を観察してください
console.log("1")
console.log("2") // 等上面执行完
console.log("3")
// 输出:1, 2, 3console.log("1")
setTimeout(() => console.log("2"), 1000)
console.log("3")
// 输出:1, 3, 2💡 識別のコツ
async/await を見たら → 時間のかかる操作を待っているfetch() を見たら → サーバーからデータを取得しているtry/catch を見たら → 発生する可能性のあるエラーを処理している「マイクロタスク/マクロタスク」といった用語は使わず、シンプルなモデルで理解しましょう:
JS は「一人用の作業机」で、同時に一つのことしかできませんが、「TODO 付箋ボード」(タスクキュー)があります。
待つ必要がある操作(ネットワークリクエスト、タイマー)に遭遇すると、JS は愚直に待つのではなく、「待ち終わったら何をするか」を付箋に書いて貼り、自分はそのまま実行を続けます。現在の処理が終わってから、付箋ボードを確認します。
console.log("1")
setTimeout(() => console.log("2"), 0) // 0 秒でも、後回しにされる
console.log("3")
// 出力:1, 3, 2(1, 2, 3 ではない!)なぜか?
console.log("1") を実行 → 1 を出力setTimeout に遭遇 → コールバックを付箋ボードに貼り、続行console.log("3") を実行 → 3 を出力setTimeout のコールバックを実行 → 2 を出力👇 実際に試してみよう:コードの実行順序を観察してください
执行顺序:还未开始
代码书写顺序:1, 2, 3, 4, 5
代码从上到下写的,但执行顺序不一定从上到下——因为异步操作会被"推迟"到当前代码执行完之后。
💡 問題が起きたら?
AI コードでデータがまだ取得できていないのにページがレンダリングされた場合、AI にこう伝えてください:「データの読み込みが完了する前にレンダリングが始まっています。loading 状態を追加して、データが到着してからレンダリングするようにしてください」
AI が生成した React/Vue コードの最初の行はほぼ常に import です。
import = 他のファイルから機能を読み込む
// ユーティリティファイルから関数を読み込む
import { formatDate } from './utils'
// サードパーティパッケージから読み込む
import React from 'react'
import { useState } from 'react'export = 機能を外部に公開して他の人が使えるようにする
// utils.js
export function formatDate(date) {
// ...
}
// またはデフォルトエクスポート
export default function formatDate(date) {
// ...
}npm パッケージ = 他の人が書いたツール、インストールすれば使える
// パッケージをインストール:npm install lodash
// パッケージを使用
import _ from 'lodash'💡 識別のコツ
import を見たら → 他のファイルから機能を読み込んでいるexport を見たら → 機能を外部に公開しているfrom 'react' を見たら → React パッケージから読み込んでいるfrom './utils' を見たら → ローカルファイルから読み込んでいる🤔 核心的な問い
ここまで多くの構文を学んだが、実際に AI のコードを手にしたときどう使うのか? どうやって素早くコードを読み解くのか? エラーに遭遇したらどうするのか? どうやって AI に正確にコードを修正してもらうのか?
4 ステップ法:
| ステップ | 何を見るか | 例 |
|---|---|---|
| 第一步:全体構造を見る | 関数はいくつあるか?それぞれ何をするか? | loadData() はデータ読み込み、renderList() はリスト表示 |
| 第二步:エントリポイントを探す | プログラムはどこから実行を開始するか? | addEventListener('click', ...) クリック時に開始 |
| 第三步:データフローを追跡 | データはどこから来て、どこに行くか? | API から取得 → 解析 → ページにレンダリング |
| 第四步:詳細ロジックを見る | 具体的な関数内でどう処理しているか? | ループ、判断、計算 |
第 1 章のコード例で完全な「読み方デモ」をやってみましょう:
// 第一步:全体構造
// - 色の配列
// - 現在のインデックスを記録する変数
// - ボタンのクリックイベント
// 第二步:エントリポイント
// button.addEventListener('click', ...) → ボタンクリック時に実行
// 第三步:データフロー
// colors(色配列)→ currentIndex(現在のインデックス)→ backgroundColor(背景色)
// 第四步:詳細ロジック
// currentIndex = (currentIndex + 1) % colors.length
// この式の意味:毎回 +1 するが、配列の長さを超えない(循環)| エラー | 平易な説明 | AI への伝え方 |
|---|---|---|
TypeError: Cannot read properties of undefined | 存在しないものから値を取得しようとしている | 「X 行目でエラー、変数 XXX が undefined です。代入ロジックを確認してください」 |
ReferenceError: xxx is not defined | 宣言されていない変数名を使っている | 「変数 xxx が定義されていません。スペルミスかインポート忘れではないですか」 |
TypeError: xxx is not a function | 関数ではないものを関数として呼び出している | 「xxx は関数ではありません。その型と出所を確認してください」 |
SyntaxError: Unexpected token | 構文エラー(括弧の不一致、カンマ忘れなど) | 「X 行目に構文エラーがあります。括弧と句読点を確認してください」 |
CORS error | ブラウザがクロスオリジンリクエストをブロック | 「CORS エラーが発生しました。クロスオリジンリソース共有を設定する必要があります」 |
404 Not Found | リクエストしたリソースが存在しない | 「API が 404 を返しています。エンドポイントのアドレスが正しいか確認してください」 |
初心者と熟練開発者の差は、往々にして問題説明の正確さに現れます。
| ❌ 悪い説明 | ✅ 良い説明 |
|---|---|
| 「コードにバグがある」 | 「削除ボタンをクリックすると、現在の項目ではなく最後の項目が削除されます」 |
| 「スタイルがおかしい」 | 「タイトルが中央揃えになるべきですが、左揃えになっています」 |
| 「データが表示されない」 | 「fetch リクエストはデータを返していますが(コンソールで確認できます)、ページが再レンダリングされていません」 |
| 「機能を追加して」 | 「ユーザー一覧ページに検索ボックスを追加して、入力時に name フィールドで曖昧一致するようにリストをリアルタイムフィルタリングしてください」 |
| 「クリックしても反応がない」 | 「ボタンをクリックするとコンソールに 'Cannot read property of undefined' エラーが表示され、エラーは X 行目です」 |
実践練習:
// バグのあるコード
function deleteTodo(index) {
todos.splice(index, 1) // 常に最後の項目を削除してしまう
}
// エラー現象:どの削除ボタンを押しても、最後の項目が削除される❌ 悪い説明: 「削除機能にバグがある」
✅ 良い説明: 「削除ボタンをクリックすると、現在の項目ではなく最後の項目が削除されます。コードでは splice(index, 1) を使っていますが、index が正しくない可能性があります。各項目の一意な id を使って削除対象をマッチングするように変更する必要があります。」
const/let を見たら → 変数が再代入可能かどうかがわかる{} を見たら → オブジェクト / [] を見たら → 配列{...obj} や [...arr] を見たら → コピーを作成しているfunction や => を見たら → 繰り返し実行可能な操作を定義しているif/else や ? : を見たら → コードが判断を行っている.map() / .filter() を見たら → 配列を変換またはフィルタリングしているdocument.querySelector を見たら → Web ページの要素を検索しているaddEventListener を見たら → ユーザー操作を監視しているasync/await を見たら → 時間のかかる操作を待っているimport/export を見たら → モジュールを読み込みまたはエクスポートしている各章の「深掘り」部分をしっかり読んだなら、以下の核心概念も習得しています:
これらの概念は、問題の特定をより速くします。
💡 問題が起きたら AI にこう伝えよう