1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScript学習ガイド【初心者〜中級者対応】〜Mathオブジェクトとグローバルオブジェクトの理解を中心に〜

Posted at

:books: はじめに

この記事は、JavaScript初心者から中級者を対象とした体系的な学習ガイドです。特に Math オブジェクトや グローバルオブジェクト など、JavaScriptの全体像を構造的に理解することに重点を置いており、教材や研修カリキュラムにも応用可能な内容となっています。

:pushpin: 対象読者

  • JavaScriptの基本構文は理解しているが、オブジェクト体系が曖昧な方
  • ビルトインオブジェクトを体系的に学びたい方
  • 実務でJavaScriptを使い始めた方
  • プログラミング講師や教材作成に携わる方

:notebook: 学習の進め方

  1. 基礎概念の理解 → JavaScript の特徴と動作環境
  2. オブジェクト体系の把握 → グローバルオブジェクトとビルトインオブジェクト
  3. 実践的な使い方 → Mathオブジェクトの活用法
  4. 応用技術 → 実践プロジェクトでの活用

:mag: グローバルオブジェクトとビルトインオブジェクトの理解を深める

:white_check_mark: 分類の全体像

JavaScript におけるオブジェクトの分類は、実は「2種類だけ」というのはやや簡略化された理解です。
正確には以下の3階層構造で整理できます:

JavaScript オブジェクト階層
├── グローバルオブジェクト(最上位・環境依存)
│   ├── window(ブラウザ環境)
│   ├── global(Node.js環境)
│   └── globalThis(共通・ES2020以降)
│
├── ビルトインオブジェクト(組み込み・約50種類以上)
│   ├── 基本データ型関連(6種類)
│   ├── 数学・計算系(3種類)
│   ├── 文字列・テキスト系(2種類)
│   ├── コレクション系(6種類)
│   ├── 日付・時刻系(1種類)
│   ├── 正規表現・パターン系(1種類)
│   ├── エラー・例外系(8種類)
│   ├── 非同期・並行処理系(3種類)
│   ├── 関数・プロキシ系(3種類)
│   ├── 国際化・多言語系(1種類)
│   └── その他・特殊系(10種類以上)
│
└── ユーザー定義オブジェクト(開発者が作成)
    ├── リテラル記法: { name: 'value' }
    ├── コンストラクタ関数: function MyClass() {}
    ├── ES6クラス: class MyClass {}
    └── ファクトリー関数: function createObject() {}

:small_blue_diamond: 1. グローバルオブジェクトとは?

JavaScriptの最上位に常に存在するオブジェクトで、すべての変数や関数の最終的な親となります。

環境 オブジェクト名 説明
ブラウザ window HTMLページのウィンドウを表現
Node.js global Node.js実行環境のグローバル領域
共通(ES2020以降) globalThis 環境に依存しない統一アクセス
// ビルトインオブジェクトもグローバルオブジェクトのプロパティ
console.log(globalThis.Math === Math);     // true
console.log(globalThis.Array === Array);   // true
console.log(globalThis.Object === Object); // true

// 環境確認
if (typeof window !== 'undefined') {
  console.log('ブラウザ環境');
} else if (typeof global !== 'undefined') {
  console.log('Node.js環境');
}

:small_blue_diamond: 2. ビルトインオブジェクト(Built-in Objects)の完全分類

JavaScriptに最初から組み込まれているオブジェクト。2023年現在、約50種類以上が存在します。


:clipboard: 主要ビルトインオブジェクト完全一覧

:1234: 基本データ型関連(6種類)

オブジェクト 用途 主要メソッド・プロパティ
Object すべてのオブジェクトの基本 keys(), values(), entries(), assign() Object.keys({a:1, b:2})
Array 配列操作 map(), filter(), reduce(), push(), pop() [1,2,3].map(x => x*2)
String 文字列処理 slice(), split(), replace(), trim() "hello".toUpperCase()
Number 数値処理 parseInt(), parseFloat(), isNaN(), isInteger() Number.parseInt("123")
Boolean 真偽値処理 valueOf(), toString() Boolean("false")
Symbol 一意識別子 for(), keyFor(), iterator Symbol("id")
基本データ型の実用例を見る
// 基本データ型の活用例
const user = { name: "Taro", age: 30, city: "Tokyo" };

// Object: オブジェクト操作
console.log(Object.keys(user));      // ["name", "age", "city"]
console.log(Object.values(user));    // ["Taro", 30, "Tokyo"]
console.log(Object.entries(user));   // [["name", "Taro"], ["age", 30], ["city", "Tokyo"]]

// Array: 配列操作
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);         // [2, 4, 6, 8, 10]
const evens = numbers.filter(n => n % 2 === 0);  // [2, 4]
const sum = numbers.reduce((a, b) => a + b, 0);  // 15

// String: 文字列操作
const text = "  Hello World  ";
console.log(text.trim().toUpperCase()); // "HELLO WORLD"
console.log(text.split(" "));           // ["", "", "Hello", "World", "", ""]

// Number: 数値操作
console.log(Number.parseInt("123.45")); // 123
console.log(Number.parseFloat("123.45")); // 123.45
console.log(Number.isInteger(123.45)); // false

:abacus: 数学・計算系(3種類)

オブジェクト 用途 主要メソッド・プロパティ
Math 数学関数・定数 random(), floor(), ceil(), round(), PI Math.random()
BigInt 大きな整数 BigInt(), toString(), valueOf() BigInt(123)
Intl.NumberFormat 数値フォーマット format(), formatToParts() 通貨・パーセント表示
数学・計算系の実用例を見る
// Math: 基本的な数学計算
console.log(Math.random());              // 0以上1未満の乱数
console.log(Math.floor(4.7));            // 4(切り捨て)
console.log(Math.ceil(4.1));             // 5(切り上げ)
console.log(Math.round(4.5));            // 5(四捨五入)
console.log(Math.max(1, 5, 3));          // 5(最大値)
console.log(Math.min(1, 5, 3));          // 1(最小値)
console.log(Math.PI);                    // 3.141592653589793

// 実用的な乱数生成
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomInt(1, 100)); // 1〜100の整数乱数

// BigInt: JavaScriptの安全な整数範囲を超える計算
const bigNumber = BigInt(9007199254740991); // Number.MAX_SAFE_INTEGER
console.log(bigNumber + 1n); // 9007199254740992n

// Intl.NumberFormat: 国際化対応数値フォーマット
const currency = new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
});
console.log(currency.format(1234567)); // "¥1,234,567"

:pencil2: 文字列・テキスト系(2種類)

オブジェクト 用途 主要メソッド・プロパティ
String 文字列操作 charAt(), substring(), indexOf(), match() "text".charAt(0)
RegExp 正規表現 test(), exec(), match(), replace() /\d+/.test("123")
文字列・正規表現の実用例を見る
// String: 高度な文字列操作
const text = "JavaScript Programming";

console.log(text.charAt(0));                    // "J"
console.log(text.substring(0, 10));             // "JavaScript"
console.log(text.indexOf("Script"));            // 4
console.log(text.includes("Program"));          // true
console.log(text.startsWith("Java"));           // true
console.log(text.endsWith("ing"));              // true

// 文字列の分割と結合
const words = text.split(" ");                  // ["JavaScript", "Programming"]
console.log(words.join("-"));                  // "JavaScript-Programming"

// RegExp: 正規表現によるパターンマッチング
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailPattern.test("user@example.com"));    // true
console.log(emailPattern.test("invalid-email"));       // false

// 実用的なバリデーションパターン
const patterns = {
  email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
  phone: /^\d{3}-\d{4}-\d{4}$/,
  zipcode: /^\d{3}-\d{4}$/,
  url: /^https?:\/\/.+/,
  password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
};

// バリデーション関数
function validateInput(type, value) {
  return patterns[type]?.test(value) || false;
}

console.log(validateInput('email', 'user@example.com'));    // true
console.log(validateInput('phone', '090-1234-5678'));       // true

:package: コレクション系(6種類)

オブジェクト 用途 主要メソッド・プロパティ
Array 順序付きリスト forEach(), some(), every(), find() arr.forEach(fn)
Set 重複なし集合 add(), delete(), has(), clear() new Set([1,2,3])
Map キー値ペア set(), get(), delete(), has() new Map()
WeakSet 弱参照集合 add(), delete(), has() ガベージコレクション対応
WeakMap 弱参照マップ set(), get(), delete(), has() ガベージコレクション対応
TypedArray 型付き配列 Int8Array, Float32Array など バイナリデータ処理
コレクション系の実用例を見る
// Array: 配列の高度な操作
const fruits = ["apple", "banana", "orange", "apple"];

console.log(fruits.some(f => f === "banana"));    // true(条件に合う要素が1つでもあるか)
console.log(fruits.every(f => f.length > 3));     // true(すべての要素が条件に合うか)
console.log(fruits.find(f => f.startsWith("o"))); // "orange"(条件に合う最初の要素)
console.log(fruits.findIndex(f => f === "banana")); // 1(条件に合う要素のインデックス)

// Set: 重複を排除した集合
const uniqueFruits = new Set(fruits);
console.log([...uniqueFruits]); // ["apple", "banana", "orange"]

uniqueFruits.add("grape");
console.log(uniqueFruits.has("apple"));  // true
console.log(uniqueFruits.size);          // 4

// Map: キー値ペアのデータ構造
const userRoles = new Map();
userRoles.set("user1", "admin");
userRoles.set("user2", "editor");
userRoles.set("user3", "viewer");

console.log(userRoles.get("user1"));     // "admin"
console.log(userRoles.has("user4"));     // false
console.log(userRoles.size);             // 3

// Map は任意の型をキーにできる
const objectMap = new Map();
const keyObj = { id: 1 };
objectMap.set(keyObj, "オブジェクトをキーとした値");
console.log(objectMap.get(keyObj));      // "オブジェクトをキーとした値"

// TypedArray: 効率的な数値配列
const bytes = new Uint8Array([255, 254, 253]);
console.log(bytes[0]);    // 255
console.log(bytes.length); // 3

:calendar: 日付・時刻系(1種類)

オブジェクト 用途 主要メソッド・プロパティ
Date 日付時刻操作 getFullYear(), getMonth(), setDate(), toISOString() new Date()
日付・時刻系の実用例を見る
// Date: 日付・時刻の操作
const now = new Date();
console.log(now.getFullYear());         // 2025
console.log(now.getMonth());            // 5(6月、0から始まる)
console.log(now.getDate());             // 23
console.log(now.getDay());              // 1(月曜日、0=日曜日)

// 特定の日付を作成
const specificDate = new Date(2025, 5, 23, 14, 30, 0); // 2025年6月23日 14:30:00
console.log(specificDate.toString());

// 日付の計算
const tomorrow = new Date(now);
tomorrow.setDate(now.getDate() + 1);
console.log(tomorrow.toDateString());

// フォーマット
console.log(now.toISOString());         // "2025-06-23T05:30:00.000Z"
console.log(now.toLocaleDateString());  // "2025/6/23"
console.log(now.toLocaleTimeString());  // "14:30:00"

// 日付の差分計算
const startDate = new Date('2025-01-01');
const endDate = new Date('2025-06-23');
const diffTime = endDate - startDate;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
console.log(`${diffDays}日経過`); // "173日経過"

:x: エラー・例外系(8種類)

オブジェクト 用途 発生タイミング
Error 汎用エラー throw new Error() カスタムエラー
SyntaxError 構文エラー パース時 eval("var 123")
TypeError 型エラー 型が不正 null.property
ReferenceError 参照エラー 未定義変数 unknownVar
RangeError 範囲エラー 範囲外アクセス new Array(-1)
URIError URI エラー 不正なURI decodeURI("%")
EvalError eval エラー eval実行時 非推奨
AggregateError 複数エラー Promise.any等 ES2021
エラーハンドリングの実用例を見る
// Error: カスタムエラーの作成と処理
class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}

function validateAge(age) {
  if (typeof age !== 'number') {
    throw new TypeError('年齢は数値で入力してください');
  }
  if (age < 0 || age > 150) {
    throw new RangeError('年齢は0から150の間で入力してください');
  }
  if (age < 18) {
    throw new ValidationError('18歳以上である必要があります', 'age');
  }
  return true;
}

// エラーハンドリング
try {
  validateAge("25");  // TypeError
} catch (error) {
  if (error instanceof TypeError) {
    console.log('型エラー:', error.message);
  } else if (error instanceof RangeError) {
    console.log('範囲エラー:', error.message);
  } else if (error instanceof ValidationError) {
    console.log('バリデーションエラー:', error.message, 'フィールド:', error.field);
  }
}

:zap: 非同期・並行処理系(3種類)

オブジェクト 用途 主要メソッド・プロパティ
Promise 非同期処理 then(), catch(), finally(), all(), race() new Promise()
AsyncFunction 非同期関数 async/await 構文 async function
GeneratorFunction ジェネレータ yield, next() function*
非同期処理の実用例を見る
// Promise: 非同期処理の基本
function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (userId > 0) {
        resolve({ id: userId, name: `User${userId}`, email: `user${userId}@example.com` });
      } else {
        reject(new Error('無効なユーザーIDです'));
      }
    }, 1000);
  });
}

// async/await: より直感的な非同期処理
async function getUsersData() {
  try {
    console.log('ユーザーデータ取得開始...');
    
    const user1 = await fetchUserData(1);
    console.log('1番目のユーザー:', user1);
    
    // 並行実行
    const [user2, user3] = await Promise.all([
      fetchUserData(2),
      fetchUserData(3)
    ]);
    
    console.log('2, 3番目のユーザー:', user2, user3);
    
  } catch (error) {
    console.error('ユーザーデータ取得エラー:', error.message);
  }
}

// Generator: イテレータとして機能する特殊な関数
function* numberGenerator(max) {
  let current = 1;
  while (current <= max) {
    yield current;
    current++;
  }
}

// for...of でジェネレータを使用
for (const num of numberGenerator(3)) {
  console.log(num); // 1, 2, 3
}

:wrench: 関数・プロキシ系(3種類)

オブジェクト 用途 主要メソッド・プロパティ
Function 関数オブジェクト call(), apply(), bind(), length, name fn.call()
Proxy オブジェクト代理 get, set, has, deleteProperty new Proxy()
Reflect オブジェクト操作 get(), set(), has(), deleteProperty() Reflect.get()
関数・プロキシ系の実用例を見る
// Function: 関数の高度な操作
function greet(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}

const person = { name: 'Taro' };

// call: thisを指定して関数を実行
console.log(greet.call(person, 'Hello', '!')); // "Hello, Taro!"

// apply: 引数を配列で渡す
console.log(greet.apply(person, ['Hi', '.'])); // "Hi, Taro."

// bind: thisが固定された新しい関数を作成
const boundGreet = greet.bind(person, 'Good morning');
console.log(boundGreet('.')); // "Good morning, Taro."

// Proxy: オブジェクトの操作をカスタマイズ
const user = { name: 'Taro', age: 30 };

const userProxy = new Proxy(user, {
  get(target, property) {
    console.log(`プロパティ "${property}" が読み取られました`);
    return target[property];
  },
  
  set(target, property, value) {
    console.log(`プロパティ "${property}" に "${value}" が設定されました`);
    if (property === 'age' && typeof value !== 'number') {
      throw new TypeError('年齢は数値である必要があります');
    }
    target[property] = value;
    return true;
  }
});

console.log(userProxy.name); // プロパティアクセスがログ出力される
userProxy.age = 31; // プロパティ設定がログ出力される

:earth_asia: 国際化・多言語系(1種類)

オブジェクト 用途 主要メソッド・プロパティ
Intl 国際化サポート DateTimeFormat, NumberFormat, Collator new Intl.DateTimeFormat()
国際化対応の実用例を見る
// Intl: 国際化対応フォーマット

// 通貨フォーマット
const currencyFormatters = {
  yen: new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }),
  dollar: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }),
  euro: new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' })
};

const price = 1234.56;
console.log(currencyFormatters.yen.format(price));    // "¥1,235"
console.log(currencyFormatters.dollar.format(price)); // "$1,234.56"
console.log(currencyFormatters.euro.format(price));   // "1.234,56 €"

// 日付・時刻フォーマット
const date = new Date('2025-06-23T14:30:00');

const dateFormatters = {
  japanese: new Intl.DateTimeFormat('ja-JP'),
  american: new Intl.DateTimeFormat('en-US'),
  european: new Intl.DateTimeFormat('en-GB')
};

console.log(dateFormatters.japanese.format(date)); // "2025/6/23"
console.log(dateFormatters.american.format(date)); // "6/23/2025"
console.log(dateFormatters.european.format(date)); // "23/06/2025"

// 相対時間フォーマット
const relativeTimeFormatter = new Intl.RelativeTimeFormat('ja-JP');
console.log(relativeTimeFormatter.format(-1, 'day'));   // "1日前"
console.log(relativeTimeFormatter.format(2, 'hour'));   // "2時間後"
console.log(relativeTimeFormatter.format(-3, 'month')); // "3か月前"

:arrows_counterclockwise: その他・特殊系(10種類以上)

オブジェクト 用途 主要メソッド・プロパティ
JSON データシリアライゼーション parse(), stringify() JSON.parse("{}")
console デバッグ出力 log(), error(), warn(), table() console.log()
setTimeout/setInterval タイマー setTimeout(), clearTimeout() 遅延実行
encodeURI/decodeURI URL エンコーディング encodeURI(), decodeURI() URL処理
isNaN/isFinite 数値判定 isNaN(), isFinite() 数値検証
ArrayBuffer バイナリデータ slice(), byteLength 低レベルデータ操作
DataView バイナリデータビュー getInt32(), setFloat64() バイナリ操作
その他・特殊系の実用例を見る
// JSON: データの変換
const userData = {
  name: "Taro",
  age: 30,
  hobbies: ["reading", "swimming"],
  address: {
    city: "Tokyo",
    zipcode: "123-4567"
  }
};

// オブジェクト → JSON文字列
const jsonString = JSON.stringify(userData, null, 2);
console.log(jsonString);

// JSON文字列 → オブジェクト
const parsedData = JSON.parse(jsonString);
console.log(parsedData.name); // "Taro"

// console: デバッグとログ出力
console.log('基本ログ');
console.warn('警告メッセージ');
console.error('エラーメッセージ');

// テーブル表示
const users = [
  { id: 1, name: 'Taro', role: 'admin' },
  { id: 2, name: 'Hanako', role: 'user' }
];
console.table(users);

// 時間測定
console.time('処理時間');
for (let i = 0; i < 1000000; i++) {
  Math.random();
}
console.timeEnd('処理時間');

// タイマー関数
const timeoutId = setTimeout(() => {
  console.log('3秒後に実行');
}, 3000);

const intervalId = setInterval(() => {
  console.log('1秒ごとに実行');
}, 1000);

// 5秒後に繰り返し処理を停止
setTimeout(() => {
  clearInterval(intervalId);
  console.log('繰り返し処理を停止');
}, 5000);

// URL エンコーディング
const url = 'https://example.com/search?q=JavaScript 学習';
const encodedUrl = encodeURI(url);
console.log(encodedUrl); // "https://example.com/search?q=JavaScript%20%E5%AD%A6%E7%BF%92"

// 数値判定
console.log(isNaN('123'));       // false
console.log(isNaN('abc'));       // true
console.log(isFinite(100));      // true
console.log(isFinite(Infinity)); // false

// より安全な数値判定(ES6以降)
console.log(Number.isNaN('abc'));     // false(文字列は数値ではないが、NaNでもない)
console.log(Number.isNaN(NaN));       // true
console.log(Number.isFinite(100));    // true
console.log(Number.isFinite('100'));  // false(文字列なので)

// ArrayBuffer: バイナリデータの扱い
const buffer = new ArrayBuffer(16); // 16バイトのバッファ
console.log(buffer.byteLength); // 16

// DataView: バイナリデータの読み書き
const view = new DataView(buffer);
view.setInt32(0, 12345);     // 0バイト目から32bit整数を書き込み
view.setFloat64(4, 3.14159); // 4バイト目から64bit浮動小数点を書き込み

console.log(view.getInt32(0));     // 12345
console.log(view.getFloat64(4));   // 3.14159

:small_orange_diamond: 覚え方のコツ

:white_check_mark: ステップ式で覚えるのがベスト

ステージ 学ぶべきオブジェクト 覚えるべきこと 実践プロジェクト例
初級 Math, String, Array, Object, Date よく使う関数を練習 計算機、ToDoリスト、時計
中級 RegExp, JSON, Function, Promise Webアプリでの活用 バリデーション、API連携
上級 Map, Set, Symbol, Proxy, Reflect 状態管理やAPI設計 複雑なデータ構造の管理
発展 TypedArray, Intl, BigInt, WeakMap パフォーマンス・国際化 大規模アプリケーション

:white_check_mark: よく使うものからグループで覚える

🟦 数学系 → Math, Number, BigInt
🟥 配列系 → Array, Set, Map
🟨 文字列系 → String, RegExp
🟩 日付系 → Date, Intl.DateTimeFormat
🟪 非同期系 → Promise, async/await
🟫 エラー系 → Error, TypeError, ReferenceError

:white_check_mark: 実際に使って覚える

実際のプロジェクトを通じて学習することで、理解が深まります。以下に実践的なサンプルプロジェクトを紹介します。

:bulb: 実践プロジェクト例

プロジェクト1: 多機能計算機

複数のビルトインオブジェクトを組み合わせた実用的な計算機アプリです。

多機能計算機のコードを見る
class AdvancedCalculator {
  constructor() {
    this.history = new Map();
    this.operations = new Set(['+', '-', '*', '/', '^', 'sqrt', 'log']);
  }
  
  calculate(expression) {
    try {
      const result = this.evaluateExpression(expression);
      this.addToHistory(expression, result);
      return result;
    } catch (error) {
      throw new TypeError(`計算エラー: ${error.message}`);
    }
  }
  
  evaluateExpression(expr) {
    // 安全な計算処理の実装
    const sanitized = expr.replace(/[^0-9+\-*/.() ]/g, '');
    
    // Math オブジェクトを使用した高度な計算
    if (expr.includes('sqrt')) {
      const number = parseFloat(expr.replace('sqrt', ''));
      return Math.sqrt(number);
    }
    
    if (expr.includes('^')) {
      const [base, exponent] = expr.split('^').map(parseFloat);
      return Math.pow(base, exponent);
    }
    
    // 基本的な四則演算
    return Function(`"use strict"; return (${sanitized})`)();
  }
  
  addToHistory(expression, result) {
    const timestamp = new Date().toISOString();
    this.history.set(timestamp, { expression, result });
  }
  
  getHistory() {
    return Array.from(this.history.entries()).map(([time, calc]) => ({
      time: new Intl.DateTimeFormat('ja-JP', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
      }).format(new Date(time)),
      ...calc
    }));
  }
  
  clearHistory() {
    this.history.clear();
  }
  
  formatResult(result, locale = 'ja-JP', options = {}) {
    return new Intl.NumberFormat(locale, {
      minimumFractionDigits: 2,
      maximumFractionDigits: 6,
      ...options
    }).format(result);
  }
}

// 使用例
const calc = new AdvancedCalculator();

console.log(calc.calculate('10 + 5'));      // 15
console.log(calc.calculate('sqrt 16'));     // 4
console.log(calc.calculate('2 ^ 3'));       // 8
console.log(calc.formatResult(1234.5678));  // "1,234.57"
console.log(calc.getHistory());

使用オブジェクト: Map, Set, Math, Date, Intl, Error, Function

プロジェクト2: 国際化対応ユーザー管理システム

ユーザー管理システムのコードを見る
class InternationalUserManager {
  constructor(locale = 'ja-JP') {
    this.users = new Map();
    this.locale = locale;
    this.validators = this.setupValidators();
    this.formatters = this.setupFormatters();
  }
  
  setupValidators() {
    return {
      email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
      phone: {
        'ja-JP': /^\d{2,4}-\d{2,4}-\d{4}$/,
        'en-US': /^\(\d{3}\) \d{3}-\d{4}$/
      },
      zipcode: {
        'ja-JP': /^\d{3}-\d{4}$/,
        'en-US': /^\d{5}(-\d{4})?$/
      }
    };
  }
  
  setupFormatters() {
    return {
      date: new Intl.DateTimeFormat(this.locale, {
        year: 'numeric',
        month: 'long',
        day: 'numeric'
      }),
      currency: new Intl.NumberFormat(this.locale, {
        style: 'currency',
        currency: this.locale === 'ja-JP' ? 'JPY' : 'USD'
      }),
      relative: new Intl.RelativeTimeFormat(this.locale)
    };
  }
  
  addUser(userData) {
    const user = this.validateAndNormalizeUser(userData);
    const userId = Symbol('userId');
    this.users.set(userId, {
      ...user,
      createdAt: new Date(),
      lastLoginAt: null
    });
    return userId;
  }
  
  validateAndNormalizeUser(userData) {
    const errors = new Map();
    
    // メールバリデーション
    if (!this.validators.email.test(userData.email)) {
      errors.set('email', 'Invalid email format');
    }
    
    // 電話番号バリデーション
    const phonePattern = this.validators.phone[this.locale];
    if (phonePattern && !phonePattern.test(userData.phone)) {
      errors.set('phone', 'Invalid phone format for locale');
    }
    
    // 郵便番号バリデーション
    const zipcodePattern = this.validators.zipcode[this.locale];
    if (zipcodePattern && !zipcodePattern.test(userData.zipcode)) {
      errors.set('zipcode', 'Invalid zipcode format for locale');
    }
    
    if (errors.size > 0) {
      const errorList = Array.from(errors.entries()).map(([field, message]) => 
        new Error(`${field}: ${message}`)
      );
      throw new AggregateError(errorList, 'User validation failed');
    }
    
    return {
      name: userData.name.trim(),
      email: userData.email.toLowerCase(),
      phone: userData.phone,
      zipcode: userData.zipcode,
      birthDate: new Date(userData.birthDate)
    };
  }
  
  getUserProfile(userId) {
    const user = this.users.get(userId);
    if (!user) {
      throw new ReferenceError('User not found');
    }
    
    const age = this.calculateAge(user.birthDate);
    const memberSince = this.formatters.relative.format(
      -Math.floor((Date.now() - user.createdAt) / (1000 * 60 * 60 * 24)),
      'day'
    );
    
    return {
      ...user,
      age,
      memberSince,
      formattedBirthDate: this.formatters.date.format(user.birthDate),
      formattedCreatedAt: this.formatters.date.format(user.createdAt)
    };
  }
  
  calculateAge(birthDate) {
    const today = new Date();
    let age = today.getFullYear() - birthDate.getFullYear();
    const monthDiff = today.getMonth() - birthDate.getMonth();
    
    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
      age--;
    }
    
    return age;
  }
  
  searchUsers(query) {
    const results = [];
    const lowerQuery = query.toLowerCase();
    
    for (const [userId, user] of this.users) {
      if (user.name.toLowerCase().includes(lowerQuery) ||
          user.email.toLowerCase().includes(lowerQuery)) {
        results.push({ userId, ...this.getUserProfile(userId) });
      }
    }
    
    return results.sort((a, b) => 
      new Intl.Collator(this.locale).compare(a.name, b.name)
    );
  }
  
  exportUserData() {
    const userData = Array.from(this.users.entries()).map(([userId, user]) => ({
      id: userId.toString(),
      ...user,
      birthDate: user.birthDate.toISOString(),
      createdAt: user.createdAt.toISOString(),
      lastLoginAt: user.lastLoginAt?.toISOString() || null
    }));
    
    return JSON.stringify(userData, null, 2);
  }
  
  importUserData(jsonData) {
    try {
      const users = JSON.parse(jsonData);
      let importedCount = 0;
      
      for (const userData of users) {
        const normalizedUser = {
          ...userData,
          birthDate: new Date(userData.birthDate),
          createdAt: new Date(userData.createdAt),
          lastLoginAt: userData.lastLoginAt ? new Date(userData.lastLoginAt) : null
        };
        
        const userId = Symbol('importedUser');
        this.users.set(userId, normalizedUser);
        importedCount++;
      }
      
      return importedCount;
    } catch (error) {
      throw new SyntaxError(`Invalid JSON data: ${error.message}`);
    }
  }
}

// 使用例
const userManager = new InternationalUserManager('ja-JP');

try {
  const userId = userManager.addUser({
    name: '田中太郎',
    email: 'tanaka@example.com',
    phone: '090-1234-5678',
    zipcode: '123-4567',
    birthDate: '1990-05-15'
  });
  
  const profile = userManager.getUserProfile(userId);
  console.log('ユーザープロフィール:', profile);
  
  const searchResults = userManager.searchUsers('田中');
  console.log('検索結果:', searchResults);
  
} catch (error) {
  if (error instanceof AggregateError) {
    console.error('複数のバリデーションエラー:');
    error.errors.forEach(err => console.error(`- ${err.message}`));
  } else {
    console.error('エラー:', error.message);
  }
}

使用オブジェクト: Map, RegExp, Intl, Symbol, Date, JSON, Error, AggregateError


:white_check_mark: 総まとめ

よくある質問と回答

質問 回答
グローバルオブジェクトとビルトインオブジェクトの違いは? グローバルは最上位の入れ物、ビルトインはその中の便利な道具箱群
ビルトインオブジェクトは全部で何種類ある? 50種類以上(ES2023現在、全部覚える必要はない)
「2種類しかない」という認識で正しい? 厳密には「グローバル + ビルトイン + ユーザー定義」の3層構造
効率的な覚え方は? よく使う順に、カテゴリごとに、実践プロジェクトで使いながら
最初に覚えるべきオブジェクトは? Math, String, Array, Object, Date の5つ
実務で最も重要なオブジェクトは? Promise(非同期処理)、Array(データ操作)、Object(構造化)

学習チェックリスト

基礎レベル(必須)

  • Math オブジェクトで基本的な計算ができる
  • Array メソッドで配列操作ができる
  • String メソッドで文字列処理ができる
  • Object の基本操作ができる
  • Date で日付・時刻を扱える

中級レベル(推奨)

  • Promiseasync/await で非同期処理ができる
  • RegExp で文字列パターンマッチングができる
  • JSON でデータのシリアライズ・デシリアライズができる
  • MapSet を適切に使い分けられる
  • エラーハンドリングが適切にできる

上級レベル(発展)

  • ProxyReflect でメタプログラミングができる
  • Intl で国際化対応ができる
  • TypedArray でバイナリデータを扱える
  • Symbol を使った高度なオブジェクト設計ができる
  • WeakMap / WeakSet の適切な使用場面を理解している

実践プロジェクトの提案

  1. 初級: 計算機アプリ(Math, String, Array使用)
  2. 中級: ToDoアプリ(Promise, JSON, Date, RegExp使用)
  3. 上級: 多言語対応のユーザー管理システム(Intl, Map, Set, Proxy使用)

次のステップ

このガイドでJavaScriptのビルトインオブジェクト体系を理解したら、次は以下の学習に進むことをお勧めします:

  1. DOM/BOM API - ブラウザ環境特有のオブジェクト
  2. Node.js API - サーバーサイド特有のオブジェクト
  3. Web API - Fetch, WebSocket, Service Worker など
  4. フレームワーク - React, Vue.js, Angular などの学習

:pencil: 最後に

JavaScriptのビルトインオブジェクトは、すべてのJavaScript開発の基礎となる重要な知識です。この体系的な理解があることで、より高度な技術の習得もスムーズに進められるでしょう。

重要なポイント:

  • 段階的に学習:初級→中級→上級の順序で
  • 実践的に覚える:実際のプロジェクトで使いながら
  • カテゴリごとに整理:用途別にグループ化して理解
  • 頻繁に使うものから:Math, Array, String, Object, Dateを最優先

この記事が皆さんのJavaScript学習の助けとなれば幸いです。質問や追加で知りたい内容があれば、コメントでお気軽にお声がけください。


:bookmark: 参考リンク

:label: タグ

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?