はじめに
この記事は、JavaScript初心者から中級者を対象とした体系的な学習ガイドです。特に Math オブジェクトや グローバルオブジェクト など、JavaScriptの全体像を構造的に理解することに重点を置いており、教材や研修カリキュラムにも応用可能な内容となっています。
対象読者
- JavaScriptの基本構文は理解しているが、オブジェクト体系が曖昧な方
- ビルトインオブジェクトを体系的に学びたい方
- 実務でJavaScriptを使い始めた方
- プログラミング講師や教材作成に携わる方
学習の進め方
-
基礎概念の理解 → JavaScript の特徴と動作環境
-
オブジェクト体系の把握 → グローバルオブジェクトとビルトインオブジェクト
-
実践的な使い方 → Mathオブジェクトの活用法
-
応用技術 → 実践プロジェクトでの活用
グローバルオブジェクトとビルトインオブジェクトの理解を深める
分類の全体像
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() {}
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環境');
}
2. ビルトインオブジェクト(Built-in Objects)の完全分類
JavaScriptに最初から組み込まれているオブジェクト。2023年現在、約50種類以上が存在します。
主要ビルトインオブジェクト完全一覧
基本データ型関連(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"
文字列・テキスト系(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
コレクション系(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
日付・時刻系(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日経過"
エラー・例外系(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);
}
}
非同期・並行処理系(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
}
関数・プロキシ系(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; // プロパティ設定がログ出力される
国際化・多言語系(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か月前"
その他・特殊系(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
覚え方のコツ
ステップ式で覚えるのがベスト
| ステージ |
学ぶべきオブジェクト |
覚えるべきこと |
実践プロジェクト例 |
| 初級 |
Math, String, Array, Object, Date
|
よく使う関数を練習 |
計算機、ToDoリスト、時計 |
| 中級 |
RegExp, JSON, Function, Promise
|
Webアプリでの活用 |
バリデーション、API連携 |
| 上級 |
Map, Set, Symbol, Proxy, Reflect
|
状態管理やAPI設計 |
複雑なデータ構造の管理 |
| 発展 |
TypedArray, Intl, BigInt, WeakMap
|
パフォーマンス・国際化 |
大規模アプリケーション |
よく使うものからグループで覚える
🟦 数学系 → Math, Number, BigInt
🟥 配列系 → Array, Set, Map
🟨 文字列系 → String, RegExp
🟩 日付系 → Date, Intl.DateTimeFormat
🟪 非同期系 → Promise, async/await
🟫 エラー系 → Error, TypeError, ReferenceError
実際に使って覚える
実際のプロジェクトを通じて学習することで、理解が深まります。以下に実践的なサンプルプロジェクトを紹介します。
実践プロジェクト例
プロジェクト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
総まとめ
よくある質問と回答
| 質問 |
回答 |
| グローバルオブジェクトとビルトインオブジェクトの違いは? |
グローバルは最上位の入れ物、ビルトインはその中の便利な道具箱群 |
| ビルトインオブジェクトは全部で何種類ある? |
50種類以上(ES2023現在、全部覚える必要はない) |
| 「2種類しかない」という認識で正しい? |
厳密には「グローバル + ビルトイン + ユーザー定義」の3層構造
|
| 効率的な覚え方は? |
よく使う順に、カテゴリごとに、実践プロジェクトで使いながら |
| 最初に覚えるべきオブジェクトは? |
Math, String, Array, Object, Date の5つ |
| 実務で最も重要なオブジェクトは? |
Promise(非同期処理)、Array(データ操作)、Object(構造化) |
学習チェックリスト
基礎レベル(必須)
中級レベル(推奨)
上級レベル(発展)
実践プロジェクトの提案
-
初級: 計算機アプリ(Math, String, Array使用)
-
中級: ToDoアプリ(Promise, JSON, Date, RegExp使用)
-
上級: 多言語対応のユーザー管理システム(Intl, Map, Set, Proxy使用)
次のステップ
このガイドでJavaScriptのビルトインオブジェクト体系を理解したら、次は以下の学習に進むことをお勧めします:
-
DOM/BOM API - ブラウザ環境特有のオブジェクト
-
Node.js API - サーバーサイド特有のオブジェクト
-
Web API - Fetch, WebSocket, Service Worker など
-
フレームワーク - React, Vue.js, Angular などの学習
最後に
JavaScriptのビルトインオブジェクトは、すべてのJavaScript開発の基礎となる重要な知識です。この体系的な理解があることで、より高度な技術の習得もスムーズに進められるでしょう。
重要なポイント:
-
段階的に学習:初級→中級→上級の順序で
-
実践的に覚える:実際のプロジェクトで使いながら
-
カテゴリごとに整理:用途別にグループ化して理解
-
頻繁に使うものから:Math, Array, String, Object, Dateを最優先
この記事が皆さんのJavaScript学習の助けとなれば幸いです。質問や追加で知りたい内容があれば、コメントでお気軽にお声がけください。
参考リンク
タグ