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

progmraming

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

先生、前回の関数は理解できたよ!今回のオブジェクトって何?データの塊みたいなものなの?
フォックン
フォックン
いい質問だね、フォックン!オブジェクトは、関連するデータと機能をひとまとめにする「箱」のようなものだよ。現実世界の「モノ」をプログラムで表現するのにぴったりなんだ。例えば、「車」というオブジェクトには色や速度などの特性(プロパティ)と、走る・止まるなどの動作(メソッド)があるんだ 🚗
オウル先生
オウル先生

オブジェクトとは?

オブジェクトは、複数の値(プロパティ)とその関連する機能(メソッド)をひとつにまとめた集合体です。実世界の物事を表現するのに最適な方法として、多くのプログラミング言語で中心的な概念となっています。

// シンプルなオブジェクトの例
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);  // "ブラック"(存在しないプロパティにデフォルト値を設定)
分割代入ってすごく便利そう!長いプロパティ名を何度も書かなくていいんだね!
フォックン
フォックン
そうだね、フォックン!分割代入は特に複雑なオブジェクトを扱うときに読みやすさが格段に上がるよ。React などのモダンなフレームワークではよく使われる技術なんだ。プロの開発者はこういった小技を使いこなして、効率的にコードを書いているんだよ 🌟
オウル先生
オウル先生

オブジェクトのイテレーション(反復処理)

オブジェクトのすべてのプロパティを処理する方法です。

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();  // "コンテンツ編集中..."
ファクトリーパターンって何に使うの?色々な「型」のオブジェクトを作るってこと?
フォックン
フォックン
その通りだよ、フォックン!ファクトリーパターンは「オブジェクト生成の詳細を隠蔽する」のが目的なんだ。例えば、ECサイトで商品の種類ごとに異なる処理が必要な場合、ファクトリーパターンを使えば「本」も「電子機器」も同じ関数から作れて、でも内部的には違う振る舞いをさせられるんだよ。コードの見通しがよくなり、メンテナンスもしやすくなるね 🛠️
オウル先生
オウル先生

実践チャレンジ

以下の問題に挑戦してみましょう:

問題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+の機能を活用すると、より読みやすく保守しやすいコードが書ける
  • 適切なオブジェクト設計パターンを選ぶことで、コードの品質が高まる
最初は難しく感じたけど、だんだん理解できてきたよ!オブジェクトを使えば整理されたコードが書けそう!
フォックン
フォックン
よく頑張ったね、フォックン!オブジェクト指向の考え方は最初は少し抽象的に感じるけど、実践していくうちに自然と身についていくよ。これでプログラムの部品を上手に組み合わせられるようになったね。次回は非同期プログラミングについて学んでいこう。Webアプリケーションではとても重要な概念だよ!
オウル先生
オウル先生

次回予告

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

ABOUT ME
アウル先生&フォックン
アウル先生&フォックン
ブログライター
オウル先生 フォックンが運営する未経験からのプログラミング上達ガイド! プログラミング学習に興味があるけど、 「どのスクールを選べばいいか分からない…」 「自分に合った学習方法が知りたい…」 「本当にエンジニアになれるか不安…」 そんな悩みをお持ちのあなたへ。 オウル先生とフォックンが、プログラミングスクール選びから学習方法、キャリア形成まで、丁寧にサポートします! 豊富な情報と分かりやすい解説で、あなたのプログラミング学習を成功へと導きます。
記事URLをコピーしました