Closed31

JavaScriptの基礎で難しかった部分をまとめる

keikei

定数を宣言しなければいけない理由

下記のような定数宣言をしなかった場合はどうなるか?

const daysInweek = 7;

理由①:修正箇所が増えてしまう

let daysInweek = 8;

7; 
7;
7;

たとえば、daysInweekがなんらかの影響で7以外の値になった場合。
他の部分で宣言している7すべて手動で修正しないといけなくなる。

const daysInweek = 8;

8; 
8;
8;

constを使って定数宣言することで、変更箇所はひとつだけになる。

理由②:リテラル値がなにを示しているか分からない

7; // 何の値?
7;
7;

たとえば、daysInweek = 7は、1週間を7日間と定義したと分かるが、
下記のリテラル値7が何の値か、このままではわからない。

const daysInweek = 7; // 定数は7だ!

daysInweek // これは7を宣言してるんだな!
daysInweek
daysInweek 

このように書くことでdaysInweek7を宣言してると理解できる

keikei

実際のサイトはこう動く

// 定数を宣言
const maxBananas = 7; // バナナの最大選択個数を定義

// 初期状態のカートのバナナの数を変数で管理
let bananasInCart = 0; // 初期値を0に設定

// 最大選択可能数を表示
document.getElementById('max-bananas-message').textContent = `バナナは最大 ${maxBananas} 本まで選択できます。`;

ユースケース

ユーザーがネット通販サイトでバナナを購入しようとしている。このサイトでは、バナナは最大選択個数が7本に制限されている。ユーザーはバナナをカートに追加するために、現在カートに入っているバナナの数を確認することができる。

処理の流れ

keikei

代入演算子の応用

let additionResult = 2 + 5;
let result = 5;

result = result + 10;
console.log(result); // 15

フローチャート

変数名はそれぞれに意味がある

additionResultは、「足し算の結果」という意味になるため、2 + 5の計算結果を保存できる。
ただし、そのあとの処理では使用されていないので、7という結果は保持している。

resultは、「結果」という意味になるため、保持する値が最終的な結果であることを示す。
今回の例では、初期値510を加えたあとの値15が保存されている。

resultは値を更新されただけ

result = result + 10;

最初に定義された値は5で、そこに10を加え、合計15になったという結果を変数result上書きするという処理。

let(予約語)がないので、値は再宣言されたわけではない。

keikei

記号で省略可能なコード

例①:

result = result + 10;

このコードは、

result += 10;

と省略できる。

例②:

result = result + 1;
result += 1;
result ++;

これらはすべて同じ意味になる。
値が1の場合かつ、足し算か引き算の場合のみ省略可能。

keikei

返す値が異なる省略記述

let result = 5;
result = result + 1;
result += 1;
console.log(result++); // 7
console.log(result); // 8
console.log(++result); // 9

result++の場合

result++;は、後置インクリメント演算子で、現在のresultの値7を出力してからresult1増やす。

resultの場合

前の行でresult++により1増加した後のresultの値8を出力する。

++resultの場合

++resultは前置インクリメント演算子で、resultの値を先に1増加させてから、その新しい値を出力する。したがって、この行でresultの値は9となる。

keikei

間違えて改行したときの処理結果

result
++ // 間違えて改行されている
++result;

この場合、javascriptは自動的に以下のように認識する。

result;
++++result;

対処法(注意すべきこと)

  • ;(セミコロン)を正しく打つ
  • 変な改行をしない
keikei

整数、引数、戻り値はすべて意味合いが異なる

整数とは、5-7のような小数点がない数値
引数とは、プログラムや関数に渡す値のこと

しかし、これらの値を正しく理解するには関数を含めたほうがわかりやすい。

前提知識1: 関数とは

関数は「値を入れると何かをやって何かを返してくれる、処理のまとまり」

関数に処理してもらうためには、まず値を入れる
そしてこの「入れる」値を引数という。
(関数が処理して出してくる値は、戻り値という。)

参考文献:分かりそうで分からない、でも分かった気になれるIT用語辞典

前提知識2: 値とは

数字=値というのは、数学的な観点でしかない。
javaScriptでは、様々なものが「値」という言葉でまとめられている。

整数(Integer): 5-30など
浮動小数点数(Floating-point number):3.14-2.5、など
文字列(String):Hello"123"、など
ブール値(Boolean):truefalse
オブジェクト(Object):{ name: "kei", sex: men }など
配列(Array):[1, 2, 3]["apple", "banana", "cherry"]など

javaScriptは、そのままでは値の意味を正しく理解できない。
人間からすれば10は数値の10、でもjavaScriptにとっては10はなにかの値と受け取る場合もある。
この原則を理解した上で、javaScriptこの値は数字だよと教えてあげる必要がある。

結論

整数とは、javaScriptが認識する「値のひとつ」のこと。
引数は、その値を「関数」に入れる「値」を指す。

keikei

組み込み関数を使う理由

指示した通りの手順で処理した値を出し入れしてねという命令を使いまわすため。
関数を使うことで、重複して複雑になる処理を省略できる。

たとえば

10を入れて、+10した結果を処理してもらったら、戻ってきた結果が1010だった。
結果は20(数値10を数値10に足したもの)が欲しかった。

これは、JavaScriptは、値が数字なのか、文字列なのかの判別ができず、10+10と単純に合体させてしまったからだ。

値の種類と処理を命令できるのが組み込み関数

const userInput = '10'; //①
let calcResult; //②

calcResult = Number(userInput) + 10; //③
console.log(calcResult); //④

//戻り値は数値としての20

この一連の流れを追いながら組み込み関数について説明する。

const userInput = '10';で、userInput10という値だと指定する。(定数宣言)
let calcResult;で、calcResultは状況に応じて変化する値の結果を保存する箱だと指定する(変数宣言)
userInputに保存された値10と、同じ式の中に存在する値+10を入れた値を数値として処理する命令を出した組み込み関数Number()に入れる(引数)
④関数に入れた値を数値として処理したものを、数値として戻した結果を表示する(戻り値)

フローチャート(図)

keikei

組み込み関数を扱うメリット

javaScriptエンジンがあらかじめ用意してくれているタスクを処理してくれるため、ユーザーが自ら処理を定義する必要がない

関数を扱うこと自体に対して言えば、処理の流れが明示的になるというメリットがある。

処理を定義する必要がないとは

関数には「ユーザー定義関数」と「組み込み関数」の2種類がある。
ユーザー定義関数は、以下のようにあらかじめ使いまわす処理を定義しておかなければいけない。

// 関数の定義
function add(a, b) {
  return a + b;
}
// 関数の呼び出し
let result = add(5, 10);
// 出力: 15
console.log(result);

対して、組み込み関数は、javaScriptエンジンがあらかじめ用意してくれている一般的なタスクを処理する関数のプリセットのようなものなので、定義する必要がなく、臨機応変に使い分けできる。

明示的とは

JavaScriptが、値の種類を正しく判別できないとすれば、すべての値に対してこれは〇〇だよと正確に教えてあげなければいけない。

userInputを数値の指定として扱う

const userInput = 10; // 数値として10を指定
let calcResult;

calcResult = userInput + 10;
console.log(calcResult); // 出力は20

関数を使わなくても同じ処理は可能だが、処理の流れが複雑でわかりづらい。

組み込み関数は特定の処理をまとめてくれる

javaScriptは値の種類を理解できないため、正しく処理させるにはひとつずつ種類の指示が必要になる。

そこで、中に入れた値に予め決めた処理を行う箱を経由することで、わざわざ入れる値の種類を指定しなくて済むようにするのが関数だ。

難しい言葉で表現すれば、
・再利用性:同じ処理を何度も書かずに済む。
・保守性:コードの一部を変更すれば、関数を使っているすべての箇所が自動更新される。
・可読性:コードの意図が明確、明示的になるので、理解しやすい。
・抽象化:複雑な処理を関数にまとめることで効率化できる。

keikei

組み込み関数を使用する際の注意点

javaScriptでは動的型付けの特性で、使用する関数によって結果が異なる場合があっても、処理した後でなければ確認できない。

const userInput = '10.9';
let calcResult;

// 例1
calcResult = Number(userInput) + 10;
console.log(calcResult); // 20.9

// 例2
calcResult = parseInt(userInput) + 10;
console.log(calcResult); // 20.9にならず、20になる

// 例3
calcResult = parseFloat(userInput) + 10;
console.log(calcResult); // 20.9

この例では、想定する戻り値が20.9なのに、parseInt(userInput) + 10;の結果だけが20になってしまった。

parseInt()が小数点以下を無視する関数だったことが原因だ。

正しく理解して適切な組み込み関数を選択する

Number(): 全体を数値に変換する。小数点も含めて変換する場合に使用。
parseInt(): 整数に変換する。小数点以下を無視する場合に使用。
parseFloat(): 浮動小数点数に変換する。小数点を含む場合に使用。

ここで紹介したもの以外にも、様々な関数が存在する。
適切に選択しなければ、意図しない結果に繋がってしまう。

keikei

ユーザー定義関数と組み込み関数の違い

ユーザー定義関数

ユーザーが自由に使いまわす処理を定義できる関数のこと。

// 関数の定義
function add(a, b) {
  return a + b;
}
// 関数の呼び出し
let result = add(5, 10);
// 出力: 15
console.log(result);

組み込み関数

**javaScriptエンジン**があらかじめ用意している一般的なタスク処理を行う関数のプリセット。
下記の例では、全体を数値に変換するNumber()というプリセットを説明している。

const userInput = '10.9';
let calcResult;

calcResult = Number(userInput) + 10;
console.log(calcResult); // 20.9
keikei

関数はひとつに対する概念じゃない

関数は、大きく分けると以下の2種類に分類される。

  • ユーザー定義関数
  • 組み込み関数

さらに、それぞれの種類の関数には、複数の形式が存在する。

keikei

ユーザー定義関数

関数宣言 (Function Declaration)

この形式は、functionキーワードを使って関数を定義する。
スコープ内のどこからでも宣言した関数を呼び出すことができる。

function add(a, b) {
  return a + b;
}

let result = add(5, 10);
console.log(result); // 出力: 15

関数式 (Function Expression)

変数に関数を代入する形式。変数が初期化された後のみ呼び出し可能。

const multiply = function(a, b) {
  return a + b;
};

let result = multiply(5, 10);
console.log(result); // 出力: 50

アロー関数(Arrow Function)

=>を使って定義する形式の関数。通常の関数式よりも簡潔に書けるが、thisの扱いが異なるなど、注意点がある。

const subtract = (a, b) => {
  return a - b;
};

let result = subtract(10, 5);
console.log(result); // 出力: 5

即時関数 (Immediately Invoked Function Expression, IIFE)

定義と同時に実行される関数。スコープを作成して、そのスコープ内の変数が外部に影響しないようにするために使う。

(function() {
  console.log('即時関数が実行されました');
})();

再帰関数 (Recursive Function)

自分自身を呼び出す関数。特定の問題を分割して再帰的に解決する際に使う。

function factorial(n) {
  if (n === 0) {
    return 1;
  }
  return n * factorial(n - 1);
}

let result = factorial(5);
console.log(result); // 出力: 120

メソッド (Method)

オブジェクトのプロパティとして定義される関数をメソッドと呼ぶ。メソッドはオブジェクトの動作を定義する。

const person = {
  name: 'Alice',
  greet: function() {
    console.log('Hello, ' + this.name);
  }
};

person.greet(); // 出力: Hello, Alice
keikei

ユーザー定義関数の仕組み

関数の定義

function add(num1, num2) {
  return num1 + num2;
}

定義の開始:function(関数の予約語)を使って関数を定義する。上記の例では、addという名前の関数を定義している。この関数名は後で呼び出すために使う。
引数:(num1, num2)というふたつの引数を受け取る。この例では、num1num2が関数を呼び出したときに渡される値を受け取る場所。
関数本体:{...}内に関数の処理が記述される。この例では、return num1 + num2;が処理内容で、引数num1num2を足し算して、その結果を返す(return文)ことを意味する。

呼び出し

let retult = add(2, 3);

呼び出し:let retult = add(2, 3)で関数addを呼び出している。
関数の実行:関数addの内部では、return num1 + num2;が実行されている。この例では、num1には2が、num2には3が渡されているので、2 + 3の計算が行われる。
戻り値の取得:計算結果の5が、関数addから返され、その値が変数resultに代入される。

結果の出力

console.log(result); // 出力: 5

結果表示:変数resultに代入された5が、console.log(result);によって出力される。

keikei

関数にアクセス可能なスコープ範囲について

外側で定義されたものは関数からアクセスできる

const newValue = 'hello';
function add() {
  console.log(newValue);
}
add(); // 出力: hello

const newValueがグローバルスコープ(ファイル内のどこからでもアクセス可能)

関数の内側で定義されたものには外側からアクセスできない

function add() {
  const newValue = 'hello';
}
add(); // 関数を呼び出すことで、newValueが関数内で定義されるが…
console.log(typeof newValue); // 出力: undefined

関数内で定義されたものは、関数スコープという。

keikei

なぜ関数スコープが重要なのか

  • 変数の衝突を防げる
    同じ名前の変数が異なる関数内で定義されても、それぞれの関数内で独立して使用可能。

  • コードの可読性と保守性
    関数内でのみ使用される変数が、関数の外側で使用されることで発生する予期せぬエラーを防げる。

  • メモリの効率的な使用
    関数が終了すると、そのスコープ内で定義された変数はガベージコレクションによって解放される。

keikei

オブジェクト指向との関連性

関数スコープの外部からアクセスができないという考え方はオブジェクト指向プログラミングの(OOP)の概念である「カプセル化」に関連している。

keikei

JavaScript: typeof演算子の詳細

typeof演算子は、JavaScriptにおいて変数やリテラルの型を調べるために使用される重要なツール。

1. 基本的な使用方法

typeof演算子は、オペランド(評価対象)の型を示す文字列を返す。

console.log(typeof 42);          // "number"
console.log(typeof 'hello');     // "string"
console.log(typeof true);        // "boolean"
console.log(typeof undefined);   // "undefined"
console.log(typeof null);        // "object" (これは歴史的な理由による誤り)
console.log(typeof {});          // "object"
console.log(typeof []);          // "object"
console.log(typeof function(){}); // "function"

2. 返値の一覧

typeof の返値
数値 "number"
文字列 "string"
真偽値 "boolean"
undefined "undefined"
null "object"
オブジェクト "object"
配列 "object"
関数 "function"
Symbol "symbol"
BigInt "bigint"

3. 注意点

null の扱い

nullの型が"object"と返されるのは、JavaScriptの初期の実装ミスです。この挙動は後方互換性のために維持されている。

console.log(typeof null); // "object"

nullかどうかを厳密に確認するには、以下のように行う:

let value = null;
console.log(value === null); // true

配列の扱い

配列も"object"として扱われる。配列かどうかを確認するにはArray.isArray()メソッドを使用する。

let arr = [1, 2, 3];
console.log(typeof arr);        // "object"
console.log(Array.isArray(arr)); // true

4. 実践的な使用例

型チェック

function processValue(value) {
  if (typeof value === "number") {
    return value * 2;
  } else if (typeof value === "string") {
    return value.toUpperCase();
  } else {
    return "Unsupported type";
  }
}

console.log(processValue(5));      // 10
console.log(processValue("hello")); // "HELLO"
console.log(processValue(true));    // "Unsupported type"

処理フロー

未定義のチェック

function safeDivide(a, b) {
  if (typeof b === "undefined" || b === 0) {
    return "Cannot divide by zero or undefined";
  }
  return a / b;
}

console.log(safeDivide(10, 2));  // 5
console.log(safeDivide(10, 0));  // "Cannot divide by zero or undefined"
console.log(safeDivide(10));     // "Cannot divide by zero or undefined"

まとめ

  • typeof演算子は変数やリテラルの型を文字列として返す。
  • nullと配列の扱いには注意が必要。
  • 型チェックや未定義チェックなど、様々な場面で活用できる。

typeof演算子を適切に使用することで、より堅牢で型安全なJavaScriptコードを書くことができる。

keikei

型チェックの処理フロー

さらに分解

⓪関数定義

function processValue(value) {}

①入力値は数値か?

if (typeof value === 'number') {

②条件分岐
「はい」の場合は数値を2倍にして返す

return value * 2;

「いいえ」の場合は③次のチェックに進む

③入力値は文字列か?

 } else if (typeof value === 'string') {

④条件分岐
「はい」の場合は文字列を大文字に変換して返す

  return value.toUpperCase();

「いいえ」の場合は「サポートされていない型」と返す

  } else {
    return 'Unsupported type';
  }

⑤いずれかの結果を返して変数が終了する

console.log(processValue(5)); // 10
console.log(processValue('hello')); // "HELLO"
console.log(processValue(true)); // "Unsupported type"
keikei

processValue関数とは?

与えられた値の型に基づいて異なる処理を行う多機能な関数。
この関数は以下の特徴を持っている:

  • 入力値の型チェック
  • 型に応じた異なる処理の実行
  • エラーハンドリング(サポートされていない型の処理)
keikei

アロー関数の基本的な処理フロー図

解説

入力値:

処理の開始点。アロー関数に渡される引数を表す。

アロー関数の種類:

使用例に基づいて、アロー関数を5つの主要なカテゴリに分類している。

単純計算:

数値を入力として受け取り、計算を行う。
例: (a, b) => a + b

文字列操作:

文字列を処理する。
例: name => こんにちは、${name}さん!

配列操作:

配列に対して操作を行う。主にmap, filter, reduceメソッドと共に使用される。

オブジェクト処理:

オブジェクトのプロパティを操作する。
例: person => person.name

条件判断:

条件をチェックし、真偽値を返す。
例: num => num % 2 === 0

配列メソッドの詳細:

map: 各要素に関数を適用し、新しい配列を作成
filter: 条件に合う要素を選択し、新しい配列を作成
reduce: 配列の要素を集約して単一の値を生成

結果を返す:

アロー関数の処理結果が返される。

注目すべきポイント

配列操作(map, filter, reduce)のようにメソッドとアロー関数を組み合わせているものは関数型プログラミングのパターンとして非常に強力。

アロー関数は単なる構文の省略化ではなく、様々な処理パターンを簡潔に表現できるツールという点は把握しておきたい。

keikei

アロー関数の概念的な処理フロー図

解説

入力: アロー関数に渡されるデータや値を表す。

アロー関数の種類:

  • 計算: 数値を扱う演算処理
  • 文字列処理: テキストデータの加工
  • 配列操作: 複数の要素に対する処理
  • オブジェクト処理: データ構造の属性操作
  • 条件判断: 真偽値を決定する処理

処理結果:

  • 計算結果: 数値演算の出力
  • 加工されたテキスト: 文字列処理後の出力
  • 新しい配列: 配列操作後の結果
  • 処理済みオブジェクト: オブジェクト操作後の状態
  • 判定結果: 条件判断の出力

配列メソッド:

配列操作の詳細を示している。

  • 変換: 各要素に関数を適用(例:map
  • 選別: 条件に合う要素の抽出(例:filter
  • 集約: 要素を一つの値にまとめる(例:reduce
keikei

アロー関数の概念的な処理フロー図

keikei

Webサイト上でアロー関数はどう使われているか

+----------------------------+------------------------------------+
|        カテゴリー          |              応用例                |
+----------------------------+------------------------------------+
| 1. ユーザーインタラクション | - フォーム処理(入力検証、送信)   |
|                            | - ボタンクリックイベント処理       |
|                            | - 検索機能(リアルタイム検索)     |
+----------------------------+------------------------------------+
| 2. データ処理               | - リストのフィルタリング           |
|                            | - データの並び替え(ソート)       |
|                            | - ページネーション制御             |
+----------------------------+------------------------------------+
| 3. 視覚効果と表示           | - アニメーション制御               |
|                            | - モーダルウィンドウの開閉         |
|                            | - 画像ギャラリーの制御             |
+----------------------------+------------------------------------+
| 4. 計算と動的表示           | - 簡単な計算機能の実装             |
|                            | - カウントダウンタイマー           |
|                            | - 動的なグラフ・チャートの更新     |
+----------------------------+------------------------------------+
| 5. 非同期処理               | - API からのデータ取得             |
|                            | - 非同期更新処理                   |
|                            | - WebSocket を使用したリアルタイム |
|                            |   通信                             |
+----------------------------+------------------------------------+

解説

ユーザーインタラクション:

ユーザーの直接的な操作に応答する機能。入力の検証、イベント処理、即時反応する検索などが含まれる。

データ処理:

Web ページ上のデータを操作する機能。リストの絞り込み、並べ替え、大量データの分割表示などが可能。

視覚効果と表示:

ユーザーインターフェースの動的な部分を制御する。スムーズなアニメーション、ポップアップの表示、画像の切り替えなどを実現する。

計算と動的表示:

ユーザー入力に基づく計算や、時間経過に伴う表示の更新を行う。計算機能やタイマー、動的なデータビジュアライゼーションなどに使用される。

非同期処理:

サーバーとの通信や、バックグラウンドでの処理を扱う。データのフェッチ、定期的な更新、リアルタイムの双方向通信などが含まれる。

keikei

Webサイト開発における配列の用途

+------------------------+--------------------------------+---------------------------+
|         用途          |           具体例               |          重要性           |
+------------------------+--------------------------------+---------------------------+
| 1. データの表示        | - 商品リストの表示             | - 同種のデータを効率的に  |
|                        | - ナビゲーションメニューの生成 |   管理・表示できる        |
+------------------------+--------------------------------+---------------------------+
| 2. ユーザー入力の処理  | - フォームの入力値チェック     | - 複数の入力を一括で      |
|                        | - 検索クエリの処理             |   処理できる              |
+------------------------+--------------------------------+---------------------------+
| 3. 動的なコンテンツ    | - 画像ギャラリーの生成         | - ユーザー体験を向上させる|
|    生成                | - コメントセクションの更新     |   柔軟なUI生成が可能      |
+------------------------+--------------------------------+---------------------------+
| 4. データの保存と取得  | - ローカルストレージの使用     | - ユーザー設定や履歴を    |
|                        | - セッションデータの管理       |   効率的に管理できる      |
+------------------------+--------------------------------+---------------------------+
| 5. 大量のデータ処理    | - 検索結果のフィルタリング     | - 効率的な検索・ソート・  |
|                        | - データのソート               |   フィルタリングが可能    |
+------------------------+--------------------------------+---------------------------+
| 6. データの変換と集計  | - 価格の表示形式変更           | - 大量のデータに対して    |
|                        | - 総売上の計算                 |   一括で操作を適用できる  |
+------------------------+--------------------------------+---------------------------+
| 7. 非同期処理の管理    | - API リクエストの管理         | - 複数の非同期タスクを    |
|                        | - バッチ処理の実行             |   効率的に制御できる      |
+------------------------+--------------------------------+---------------------------+

配列の繰り返し処理の重要性:
1. コードの簡潔さ: 冗長なコードを減らし、可読性を向上
2. パフォーマンス: 大量のデータを効率的に処理
3. 柔軟性: データの数に応じて動的に処理を適用
4. 再利用性: 同じ処理を異なるデータセットに容易に適用可能

配列とは何か

複数の値をまとめて扱うためのデータ構造。
たとえば、商品リスト、ユーザー情報、画像ギャラリーなどの同種のデータをグループ化して管理するのに適している。

例:山田さん、男性、年齢28歳、出身国日本

const person = [
    {
        name: "山田さん",
        gender: "男性",
        age: 28,
        country: "日本"
    }
];

// データのアクセス例
console.log(person[0].name);    // "山田さん"
console.log(person[0].gender);  // "男性"
console.log(person[0].age);     // 28
console.log(person[0].country); // "日本"

データの表示

ECサイトでの商品情報(名前、価格、画像URL等)を配列で管理してページに表示する。

const products = [
  { name: "Tシャツ", price: 2000, image: "tshirt.jpg" },
  { name: "ジーンズ", price: 5000, image: "jeans.jpg" },
  // ... 他の商品
];

// 商品リストを表示する
products.forEach(product => {
  console.log(`${product.name}: ¥${product.price}`);
});

ユーザー入力の処理

フォームの入力フィールドを配列で管理して、一括でバリデーションを行う。

const formFields = ['name', 'email', 'password'];

formFields.forEach(field => {
  const value = document.getElementById(field).value;
  if (!value) {
    console.log(`${field} is required`);
  }
});

動的なコンテンツ生成

ナビゲーションメニューの項目を配列で管理して動的にHTMLを生成する。

const menuItems = ['ホーム', '商品一覧', 'お問い合わせ', 'ログイン'];

const navHTML = menuItems.map(item => `<li>${item}</li>`).join('');
document.querySelector('nav ul').innerHTML = navHTML;

データの保存と取得

ローカルストレージの使用において、ユーザー設定や履歴を配列として保存して、必要に応じて取得する。

// 閲覧履歴を保存
const viewHistory = JSON.parse(localStorage.getItem('viewHistory') || '[]');
viewHistory.push('新しく見た商品ID');
localStorage.setItem('viewHistory', JSON.stringify(viewHistory));
keikei

繰り返し処理の用途、大量のデータ処理

検査結果のフィルタリングにおいて、ユーザーの検索クエリに基づいて商品をフィルタリングする。

const searchQuery = "シャツ";
const filteredProducts = products.filter(product => 
  product.name.includes(searchQuery)
);

データの変換

価格の表示形式を変更する。たとえば、全商品の価格を税抜きから税込み表示に変換。

const productsWithTax = products.map(product => ({
  ...product,
  priceWithTax: Math.floor(product.price * 1.1)
}));

集計と分析

注文データから総売り上げ金額を計算する。

const totalSales = orders.reduce((sum, order) => sum + order.amount, 0);
keikei

配列メソッドのざっくり説明

push(), pop(), unshift(), shift() は配列の要素を追加・削除する。

slice() は配列の一部を切り出して新しい配列を作成する。

配列の繰り返し処理には for 文、forEach() メソッド、for...of 文などがある。

filter(), map(), reduce() などの高度なメソッドを使用することで、複雑なデータ処理を簡潔に書くことができる。

keikei

オブジェクトで抑えるべきポイント

  • オブジェクトは波括弧{...}で囲んで作成する。
  • プロパティはキー:値の形式で定義する。
  • ドット記法.またはブラケット記法[]でプロパティにアクセスできる。
  • メソッドはオブジェクト内で定義された関数
  • for...inループでオブジェクトすべてのプロパティを繰り返し処理できる。

for...inの繰り返し処理とは?

なぜループ処理は必要か

データの一括処理

オブジェクトに含まれる多数のプロパティを効率的に処理できるから

動的なプロパティ処理

事前にプロパティ名がわからなくても、すべてのプロパティにアクセスできるから

柔軟性と簡潔さ

オブジェクト構造が変更されてもコードの修正なしですべてのプロパティを処理できる、、各プロパティに対して同じ処理を繰り返し書く必要がなくなるから

ループ処理で何ができるか

データの表示:

オブジェクト内すべてのプロパティと値を表示する。

let person = { name: "太郎", age: 30, city: "東京" };
for (let key in person) {
    console.log(key + ": " + person[key]);
}

データの変換:

オブジェクトの値を一括で変更する。

let prices = { apple: 100, banana: 80, orange: 120 };
for (let item in prices) {
    prices[item] *= 1.1;  // 10%値上げ
}

データの集計:

オブジェクト内の数値を計算する。

let sales = { monday: 150, tuesday: 200, wednesday: 180 };
let total = 0;
for (let day in sales) {
    total += sales[day];
}
console.log("Total sales: " + total);

条件に基づくフィルタリング:

特定の条件を満たすプロパティのみを処理する。

let inventory = { apples: 5, bananas: 0, oranges: 3 };
let inStock = [];
for (let fruit in inventory) {
    if (inventory[fruit] > 0) {
        inStock.push(fruit);
    }
}
console.log("In stock: " + inStock.join(", "));

フィルタリング処理の実用例

タグによる記事の仕分け:

ブログ記事をタグでフィルタリングする
複数のタグを持つ記事から特定のタグを含む記事を抽出する

let articles = [
    { id: 1, title: "JavaScriptの基礎", tags: ["プログラミング", "JavaScript", "入門"] },
    { id: 2, title: "Reactの使い方", tags: ["プログラミング", "JavaScript", "React", "フレームワーク"] },
    { id: 3, title: "効果的なSEO対策", tags: ["マーケティング", "SEO", "Webサイト"] },
    { id: 4, title: "モダンなCSS技法", tags: ["プログラミング", "CSS", "Web開発"] }
];

function filterArticlesByTag(articles, targetTag) {
    let filteredArticles = [];
    for (let i in articles) {
        let article = articles[i];
        for (let j in article.tags) {
            if (article.tags[j].toLowerCase() === targetTag.toLowerCase()) {
                filteredArticles.push(article);
                break; // 一致するタグが見つかったらこの記事のループを抜ける
            }
        }
    }
    return filteredArticles;
}

let javascriptArticles = filterArticlesByTag(articles, "JavaScript");
console.log(javascriptArticles);
// 出力: [
//   { id: 1, title: "JavaScriptの基礎", tags: ["プログラミング", "JavaScript", "入門"] },
//   { id: 2, title: "Reactの使い方", tags: ["プログラミング", "JavaScript", "React", "フレームワーク"] }
// ]

詳細検索機能の実装:

ユーザープロフィールの詳細検索
複数の検索条件(スキル、年齢範囲、場所など)を組み合わせた検索

let users = [
    { id: 1, name: "田中太郎", age: 28, skills: ["JavaScript", "Python"], location: "東京" },
    { id: 2, name: "鈴木花子", age: 35, skills: ["Java", "C++"], location: "大阪" },
    { id: 3, name: "佐藤次郎", age: 42, skills: ["Python", "Ruby"], location: "東京" },
    { id: 4, name: "山田凛", age: 23, skills: ["JavaScript", "React"], location: "名古屋" }
];

function advancedSearch(users, criteria) {
    return users.filter(user => {
        for (let key in criteria) {
            if (key === 'skills') {
                // スキルは配列なので、一つでも一致すればOK
                if (!criteria[key].some(skill => user[key].includes(skill))) {
                    return false;
                }
            } else if (key === 'ageRange') {
                // 年齢範囲のチェック
                if (user.age < criteria[key].min || user.age > criteria[key].max) {
                    return false;
                }
            } else if (user[key] !== criteria[key]) {
                return false;
            }
        }
        return true;
    });
}

let searchCriteria = {
    skills: ["JavaScript"],
    ageRange: { min: 20, max: 30 },
    location: "東京"
};

let searchResults = advancedSearch(users, searchCriteria);
console.log(searchResults);
// 出力: [
//   { id: 1, name: "田中太郎", age: 28, skills: ["JavaScript", "Python"], location: "東京" }
// ]
keikei

クラスと配列

似ている点

  • 複数の要素を含んでいる
    配列:複数の値に順序をつけて格納する
    クラス:複数のプロパティ(データ)と方法(機能)を含む

  • インデックス / 名前でアクセスする
    配列:インデックスを使って要素にアクセスする
    クラス:プロパティ名を使ってデータにアクセスする

異なる点

  • 構造と目的が違う
    配列:同じ種類のデータを順序付けて格納する。
    クラス:関連するデータと機能をまとめて新しいを定義する。

  • データの多様性
    配列:通常は同じ型のデータを格納。(たとえば、数字の列、文字列の列)
    クラス:異なる型のデータと機能をひとつの単位として扱える。

たとえば、山田さん28歳男性出身日本…(stringnumberの複合)

  • 機能の包含
    配列:データの格納が主な目的。操作は別の関数で行う。
    クラス:データとそのデータを操作する機能(メソッド)を一緒に定義できる

  • 使用目的
    配列:データの集合を扱うときに使用する
    クラス:複雑な概念や実態をモデル化するときに使用する

使い分けのポイント

配列を使う場合

  • 同じ種類のデータを順序だてて管理したい
  • 単純なリストや集合を扱うとき
let students = ["山田", "田中", "佐藤", "鈴木"];
console.log(students[0]); // 出力: "山田"

クラスを使う場合

  • 複雑な情報(人、車、商品など)を扱いたい
  • データとデータに対する操作を一緒に定義したいとき
  • コードを理論的に構造化して再利用しやすい形にするとき
class Student {
    constructor(name, age, grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }

    introduce() {
        console.log(`私は${this.name}です。${this.age}歳で、${this.grade}年生です。`);
    }
}

let yamada = new Student("山田", 15, 2);
yamada.introduce(); // 出力: "私は山田です。15歳で、2年生です。"
keikei

クラス、コンストラクタ、オブジェクトの関係:料理の例え

  • クラス=レシピの種類(例:カレーのレシピ)
    具材、調理手順を定義する。

  • コンストラクタ=レシピの具体的な指示
    具材の量、火加減、水の量などを定義する。

  • オブジェクト=実際に作られた料理
    カレー。

class Curry {  // クラス(カレーのレシピ)
  constructor(spiceLevel, mainIngredient) {  // コンストラクタ(具体的な指示)
    this.spiceLevel = spiceLevel;
    this.mainIngredient = mainIngredient;
    this.isCooked = false;
  }

  cook() {  // メソッド(調理手順)
    console.log(`${this.mainIngredient}を使った${this.spiceLevel}辛さのカレーを作ります。`);
    this.isCooked = true;
  }

  serve() {  // メソッド(盛り付け)
    if (this.isCooked) {
      console.log("カレーをお皿に盛り付けました。いただきます!");
    } else {
      console.log("まだカレーが調理されていません。");
    }
  }
}

// オブジェクトの作成(実際の料理を作る)
let myCurry = new Curry("中辛", "チキン");
myCurry.cook();  // 出力: "チキンを使った中辛のカレーを作ります。"
myCurry.serve(); // 出力: "カレーをお皿に盛り付けました。いただきます!"

// 別のオブジェクト(別の料理)を作成
let friendsCurry = new Curry("辛口", "ビーフ");
friendsCurry.cook();  // 出力: "ビーフを使った辛口のカレーを作ります。"
このスクラップは4ヶ月前にクローズされました