【オウル先生の基礎講座】Vol.6「オブジェクトの基本を学ぼう」

プログラムをより構造的に書ける「オブジェクト」の基礎を解説!


オブジェクトとは?
オブジェクトは、複数の値(プロパティ)とその関連する機能(メソッド)をひとつにまとめた集合体です。実世界の物事を表現するのに最適な方法として、多くのプログラミング言語で中心的な概念となっています。
// シンプルなオブジェクトの例
const car = {
// プロパティ(データ)
brand: "Toyota",
model: "Prius",
year: 2023,
color: "blue",
// メソッド(機能)
start: function() {
console.log("エンジンスタート!");
},
drive: function() {
console.log("走行中...");
}
};
// オブジェクトのプロパティにアクセス
console.log(car.brand); // "Toyota"
console.log(car.year); // 2023
// オブジェクトのメソッド実行
car.start(); // "エンジンスタート!"
オブジェクトの作成方法
JavaScriptでは、オブジェクトを作成するための複数の方法があります。
1. オブジェクトリテラル
最もシンプルで一般的な方法です。波括弧 {}
を使って直接オブジェクトを定義します。
const person = {
firstName: "太郎",
lastName: "山田",
age: 30,
isEmployed: true
};
2. コンストラクタ関数
同じ構造を持つ複数のオブジェクトを作成するのに便利です。
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.greet = function() {
console.log(`こんにちは、${this.firstName}です!`);
};
}
const person1 = new Person("太郎", "山田", 30);
const person2 = new Person("花子", "鈴木", 25);
person1.greet(); // "こんにちは、太郎です!"
person2.greet(); // "こんにちは、花子です!"
3. クラス構文(ES6+)
モダンJavaScriptでは、より他の言語に近い形でオブジェクト指向プログラミングができます。
class Person {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
greet() {
console.log(`こんにちは、${this.firstName}です!`);
}
getFullName() {
return `${this.lastName} ${this.firstName}`;
}
}
const person = new Person("太郎", "山田", 30);
console.log(person.getFullName()); // "山田 太郎"
クラスってなに?さっきまでオブジェクトの話じゃなかったの?もう混乱してきた...

プロパティとメソッド
プロパティへのアクセスと変更
オブジェクトのプロパティには2つの方法でアクセスできます。
const book = {
title: "JavaScript入門",
author: "山田太郎",
"publication year": 2023 // スペースを含む名前はクォートで囲む
};
// ドット記法
console.log(book.title); // "JavaScript入門"
// ブラケット記法(変数や特殊文字を含む場合に使用)
console.log(book["author"]); // "山田太郎"
console.log(book["publication year"]); // 2023
// プロパティの変更
book.title = "JavaScript完全ガイド";
book["page count"] = 350; // 新しいプロパティ追加
// プロパティの削除
delete book.author;
オブジェクト内のメソッド
メソッドはオブジェクトに属する関数です。this
キーワードを使って自身のプロパティにアクセスできます。
const calculator = {
value: 0,
add(num) {
this.value += num;
return this; // メソッドチェーン用
},
subtract(num) {
this.value -= num;
return this;
},
multiply(num) {
this.value *= num;
return this;
},
getValue() {
return this.value;
}
};
// メソッドチェーンの例
calculator.add(5).multiply(2).subtract(3);
console.log(calculator.getValue()); // 7
オブジェクトの高度な操作
オブジェクトの結合
// Object.assign を使用
const defaults = { theme: "light", fontSize: 16 };
const userPrefs = { theme: "dark" };
const settings = Object.assign({}, defaults, userPrefs);
console.log(settings); // { theme: "dark", fontSize: 16 }
// スプレッド構文(ES6+)
const mergedSettings = { ...defaults, ...userPrefs };
console.log(mergedSettings); // { theme: "dark", fontSize: 16 }
プロパティのショートハンド
変数名とプロパティ名が同じ場合は省略できます。
javascriptconst name = "山田太郎";
const age = 30;
// ES6前
const user1 = { name: name, age: age };
// ES6以降(ショートハンド)
const user2 = { name, age };
分割代入(Destructuring)
オブジェクトから必要なプロパティを簡潔に取り出せます。
const product = {
name: "スマートフォン",
price: 60000,
manufacturer: "TechCo",
specs: {
cpu: "Snapdragon 8",
ram: "8GB",
storage: "128GB"
}
};
// 基本的な分割代入
const { name, price } = product;
console.log(name); // "スマートフォン"
// ネストしたオブジェクトの分割代入
const { specs: { cpu, ram } } = product;
console.log(cpu); // "Snapdragon 8"
// デフォルト値の設定
const { color = "ブラック" } = product;
console.log(color); // "ブラック"(存在しないプロパティにデフォルト値を設定)


オブジェクトのイテレーション(反復処理)
オブジェクトのすべてのプロパティを処理する方法です。
const person = {
name: "山田太郎",
age: 30,
job: "エンジニア",
hobbies: ["読書", "旅行", "プログラミング"]
};
// for...in ループ
for (const key in person) {
if (person.hasOwnProperty(key)) { // 継承プロパティを除外
console.log(`${key}: ${person[key]}`);
}
}
// Object.keys()
const keys = Object.keys(person);
console.log(keys); // ["name", "age", "job", "hobbies"]
// Object.values()
const values = Object.values(person);
console.log(values); // ["山田太郎", 30, "エンジニア", Array(3)]
// Object.entries()
const entries = Object.entries(person);
entries.forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
プロトタイプと継承
JavaScriptのオブジェクト指向は「プロトタイプベース」です。すべてのオブジェクトは「プロトタイプ」を持ち、そこからプロパティやメソッドを継承します。
プロトタイプチェーン
// コンストラクタ関数
function Animal(name) {
this.name = name;
}
// プロトタイプにメソッドを追加
Animal.prototype.speak = function() {
console.log(`${this.name}が鳴いています`);
};
// 子クラス
function Dog(name, breed) {
Animal.call(this, name); // 親コンストラクタ呼び出し
this.breed = breed;
}
// Dogのプロトタイプを設定
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 子クラス独自のメソッド追加
Dog.prototype.bark = function() {
console.log("ワンワン!");
};
const dog = new Dog("ポチ", "柴犬");
dog.speak(); // "ポチが鳴いています"
dog.bark(); // "ワンワン!"
モダンな継承(ES6クラス)
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}が鳴いています`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 親クラスのコンストラクタ呼び出し
this.breed = breed;
}
bark() {
console.log("ワンワン!");
}
// メソッドのオーバーライド
speak() {
super.speak(); // 親クラスのメソッド呼び出し
console.log(`${this.name}は${this.breed}です`);
}
}
const dog = new Dog("ポチ", "柴犬");
dog.speak();
// "ポチが鳴いています"
// "ポチは柴犬です"
実践的なオブジェクト設計パターン
1. モジュールパターン(プライベートデータ)
const counter = (function() {
// プライベート変数
let count = 0;
// 公開API
return {
increment() {
return ++count;
},
decrement() {
return --count;
},
getValue() {
return count;
}
};
})();
console.log(counter.getValue()); // 0
counter.increment();
console.log(counter.getValue()); // 1
// count には直接アクセスできない
2. ファクトリーパターン
様々な種類のオブジェクトを作成するための一貫したインターフェースを提供します。
function createUser(type) {
const user = {
id: Math.random().toString(36).substr(2, 9),
createdAt: new Date(),
// 共通メソッド
describe() {
console.log(`ユーザータイプ: ${this.type}`);
}
};
// タイプ別の設定
switch(type) {
case 'admin':
user.type = 'admin';
user.accessLevel = 'all';
user.manageUsers = function() { console.log("ユーザー管理中..."); };
break;
case 'editor':
user.type = 'editor';
user.accessLevel = 'content';
user.editContent = function() { console.log("コンテンツ編集中..."); };
break;
default:
user.type = 'basic';
user.accessLevel = 'read';
}
return user;
}
const admin = createUser('admin');
const editor = createUser('editor');
admin.manageUsers(); // "ユーザー管理中..."
editor.editContent(); // "コンテンツ編集中..."


実践チャレンジ
以下の問題に挑戦してみましょう:
問題1:書籍管理システム
書籍のタイトル、著者、出版年、既読状態を管理するBookオブジェクトを作成し、複数の本を配列で管理する仕組みを実装してください。
問題2:ショッピングカート
商品名、価格、数量を持つ商品オブジェクトと、それらを管理し合計金額を計算できるショッピングカートを実装してください。
問題3:シンプルなブログシステム
タイトル、本文、作成日、著者を持つ記事オブジェクトと、その記事を管理・検索できるブログシステムを実装してください。
解答例
問題1の解答例:書籍管理システム 👀
// 問題1の解答:書籍管理システム class Book { constructor(title, author, year) { this.title = title; this.author = author; this.year = year; this.isRead = false; } markAsRead() { this.isRead = true; console.log(${this.title}を読み終わりました!); } getSummary() { return 『${this.title}』(${this.author}著, ${this.year}年); } } class BookList { constructor() { this.books = []; } addBook(book) { this.books.push(book); } getUnreadBooks() { return this.books.filter(book => !book.isRead); } getBooksByAuthor(author) { return this.books.filter(book => book.author === author); } } // 使用例 const bookList = new BookList(); bookList.addBook(new Book("JavaScript完全ガイド", "山田太郎", 2023)); bookList.addBook(new Book("Reactハンズオン", "佐藤花子", 2022)); bookList.addBook(new Book("プログラミング入門", "山田太郎", 2021)); console.log(bookList.getBooksByAuthor("山田太郎"));
問題2の解答例:ショッピングカート 👀
// 問題2の解答:ショッピングカート class Product { constructor(name, price) { this.name = name; this.price = price; } } class CartItem { constructor(product, quantity = 1) { this.product = product; this.quantity = quantity; } getSubtotal() { return this.product.price * this.quantity; } } class ShoppingCart { constructor() { this.items = []; } addItem(product, quantity = 1) { // 既存の商品があれば数量を増やす const existingItem = this.items.find(item => item.product.name === product.name); if (existingItem) { existingItem.quantity += quantity; } else { this.items.push(new CartItem(product, quantity)); } } removeItem(productName) { const index = this.items.findIndex(item => item.product.name === productName); if (index !== -1) { this.items.splice(index, 1); } } updateQuantity(productName, quantity) { const item = this.items.find(item => item.product.name === productName); if (item) { item.quantity = quantity; } } getTotal() { return this.items.reduce((total, item) => total + item.getSubtotal(), 0); } checkout() { const total = this.getTotal(); console.log(合計金額: ${total}円で購入が完了しました!); this.items = []; // カートをクリア return total; } } // 使用例 const cart = new ShoppingCart(); cart.addItem(new Product("JavaScript本", 3000), 2); cart.addItem(new Product("キーボード", 8000)); console.log(現在のカート合計: ${cart.getTotal()}円);
問題3の解答例:シンプルなブログシステム 👀
// 問題3の解答:シンプルなブログシステム class BlogPost { constructor(title, content, author) { this.title = title; this.content = content; this.author = author; this.createdAt = new Date(); this.tags = []; this.comments = []; } addTag(tag) { if (!this.tags.includes(tag)) { this.tags.push(tag); } } addComment(user, text) { this.comments.push({ user, text, createdAt: new Date() }); } getSummary() { // 本文の最初の100文字を要約として返す return this.content.length > 100 ? this.content.substring(0, 100) + '...' : this.content; } } class BlogSystem { constructor() { this.posts = []; } createPost(title, content, author) { const post = new BlogPost(title, content, author); this.posts.push(post); return post; } getAllPosts() { return this.posts; } getPostsByAuthor(author) { return this.posts.filter(post => post.author === author); } findPostsByTag(tag) { return this.posts.filter(post => post.tags.includes(tag)); } searchPosts(keyword) { const lowerKeyword = keyword.toLowerCase(); return this.posts.filter(post => post.title.toLowerCase().includes(lowerKeyword) || post.content.toLowerCase().includes(lowerKeyword) ); } getRecentPosts(count = 5) { // 投稿日時で降順ソートして最新の記事を返す return [...this.posts] .sort((a, b) => b.createdAt - a.createdAt) .slice(0, count); } } // 使用例 const blog = new BlogSystem(); // 記事を作成 const post1 = blog.createPost( "JavaScript入門", "JavaScriptは、Webページに動きを追加するためのプログラミング言語です。", "山田太郎" ); post1.addTag("JavaScript"); post1.addTag("プログラミング"); const post2 = blog.createPost( "CSSのフレックスボックス", "フレックスボックスは、CSSのモダンなレイアウト手法です。", "佐藤花子" ); post2.addTag("CSS"); post2.addTag("デザイン"); post1.addComment("鈴木次郎", "とても分かりやすい記事でした!"); // 検索と絞り込み console.log(blog.getPostsByAuthor("山田太郎")); console.log(blog.findPostsByTag("JavaScript")); console.log(blog.searchPosts("CSS")); console.log(blog.getRecentPosts(3));
まとめ
オブジェクト指向プログラミングの基本を理解すると、より構造化されたコードが書けるようになります:
- カプセル化: 関連するデータと機能をまとめる
- 継承: 親クラスの特性を子クラスで再利用
- ポリモーフィズム: 同じインターフェースで異なる実装を持つ
重要なポイント:
- JavaScriptのオブジェクトは非常に柔軟で、動的にプロパティを追加・削除できる
- モダンなES6+の機能を活用すると、より読みやすく保守しやすいコードが書ける
- 適切なオブジェクト設計パターンを選ぶことで、コードの品質が高まる


次回予告
Vol.7では「非同期プログラミングを理解しよう」をテーマに、コールバック、Promise、async/awaitといった非同期処理のパターンを解説します。お楽しみに! 🚀