JavaScriptのgetterとsetterを使ったアクセス制御の完全ガイド

JavaScriptにおけるgetterとsetterは、オブジェクトのプロパティに対するアクセス制御を強化するための強力なツールです。通常、オブジェクトのプロパティは直接アクセスおよび変更できますが、getterとsetterを使用すると、プロパティの読み取りや書き込み時に追加のロジックを挟むことができます。これにより、データの整合性を保ち、不正な操作を防ぐことができます。本記事では、getterとsetterの基本から高度な使い方まで、具体的な例を交えながら詳細に解説します。getterとsetterを効果的に利用することで、JavaScriptプログラムの品質と安全性を大幅に向上させる方法を学びましょう。

目次

getterとsetterの基本

getterとsetterは、オブジェクトのプロパティに対するアクセス方法を制御するための特殊なメソッドです。これらのメソッドを使用すると、プロパティの値を取得(get)したり設定(set)したりする際に追加の処理を行うことができます。

getterの基本構文

getterは、プロパティの値を取得する際に呼び出されるメソッドです。以下は、getterの基本構文です。

let obj = {
  _name: 'John',
  get name() {
    return this._name;
  }
};

console.log(obj.name); // "John"

この例では、nameプロパティの値を取得する際に、getterメソッドが呼び出され、_nameプロパティの値を返します。

setterの基本構文

setterは、プロパティの値を設定する際に呼び出されるメソッドです。以下は、setterの基本構文です。

let obj = {
  _name: 'John',
  set name(value) {
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  }
};

obj.name = 'Doe';
console.log(obj.name); // "Doe"
obj.name = ''; // "Name cannot be empty"

この例では、nameプロパティに値を設定する際に、setterメソッドが呼び出されます。setterメソッドでは、値が空でないかをチェックし、適切な値が設定されるようにしています。

getterとsetterを使うことで、オブジェクトのプロパティに対するアクセスを柔軟に制御し、データの整合性を保つことができます。

アクセス制御の重要性

JavaScriptにおけるアクセス制御は、オブジェクトのデータを安全かつ効率的に管理するために不可欠です。アクセス制御を適切に行うことで、データの一貫性を保ち、不正な操作やエラーを防ぐことができます。

データの保護

アクセス制御を行うことで、オブジェクトの内部データを保護できます。直接プロパティにアクセスさせるのではなく、getterとsetterを使って間接的に操作することで、不正なデータの変更や破壊を防ぎます。

データの検証

setterを使用することで、データを設定する際に検証ロジックを組み込むことができます。これにより、不正なデータや望ましくない値がプロパティに設定されるのを防ぐことができます。

let user = {
  _age: 25,
  set age(value) {
    if (value > 0 && value < 120) {
      this._age = value;
    } else {
      console.log('Invalid age');
    }
  }
};

user.age = 30; // Valid age
console.log(user._age); // 30
user.age = -5; // Invalid age

ロジックのカプセル化

getterとsetterを使用することで、データへのアクセス方法に対するロジックをオブジェクト内にカプセル化できます。これにより、コードの再利用性が向上し、メンテナンスが容易になります。

依存関係の管理

アクセス制御を適切に行うことで、オブジェクトの依存関係を明確に管理できます。例えば、あるプロパティの変更が他のプロパティに影響を与える場合、getterとsetterを使って依存関係を管理し、一貫性を保つことができます。

let rectangle = {
  _width: 10,
  _height: 20,
  get area() {
    return this._width * this._height;
  },
  set width(value) {
    this._width = value;
  },
  set height(value) {
    this._height = value;
  }
};

rectangle.width = 15;
console.log(rectangle.area); // 300
rectangle.height = 10;
console.log(rectangle.area); // 150

アクセス制御は、ソフトウェアの品質を向上させるための重要な手段です。getterとsetterを活用することで、安全かつ効率的なデータ管理が可能になります。

getterの使い方

getterはオブジェクトのプロパティにアクセスする際に特定の処理を実行するためのメソッドです。getterを使うことで、プロパティの値を取得する際に追加のロジックを挟むことができます。

基本的なgetterの使い方

getterを定義するには、プロパティ名の前にgetキーワードを付けます。以下は、基本的なgetterの使い方の例です。

let person = {
  _name: 'Alice',
  get name() {
    return this._name;
  }
};

console.log(person.name); // "Alice"

この例では、nameプロパティにアクセスすると、getterメソッドが呼び出され、_nameプロパティの値が返されます。

getterを使った計算プロパティ

getterを使うと、プロパティの値を動的に計算することができます。例えば、次の例では、fullNameプロパティがfirstNamelastNameの値に基づいて計算されます。

let user = {
  firstName: 'John',
  lastName: 'Doe',
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
};

console.log(user.fullName); // "John Doe"

セキュリティとデータ整合性の向上

getterを使うことで、プロパティの値にアクセスする際にセキュリティチェックやデータ整合性チェックを行うことができます。例えば、次の例では、パスワードを直接表示しないようにしています。

let account = {
  _password: 'secret123',
  get password() {
    return '****';
  }
};

console.log(account.password); // "****"

このように、getterを使うことで、データの保護や不正アクセスの防止が可能になります。

例外処理の組み込み

getterを使って例外処理を組み込むこともできます。例えば、次の例では、特定の条件を満たさない場合にエラーメッセージを返すようにしています。

let product = {
  _price: 50,
  get price() {
    if (this._price < 0) {
      throw new Error('Price cannot be negative');
    }
    return this._price;
  }
};

try {
  console.log(product.price); // 50
  product._price = -10;
  console.log(product.price); // Error: Price cannot be negative
} catch (e) {
  console.log(e.message);
}

getterは、オブジェクトのプロパティにアクセスする際に柔軟なロジックを適用するための便利な方法です。これにより、コードの可読性と保守性が向上し、安全で効率的なデータ管理が可能になります。

setterの使い方

setterは、オブジェクトのプロパティに値を設定する際に特定の処理を実行するためのメソッドです。setterを使うことで、プロパティの値を設定する際に検証やデータの整形を行うことができます。

基本的なsetterの使い方

setterを定義するには、プロパティ名の前にsetキーワードを付けます。以下は、基本的なsetterの使い方の例です。

let person = {
  _name: 'Alice',
  set name(value) {
    this._name = value;
  }
};

person.name = 'Bob';
console.log(person._name); // "Bob"

この例では、nameプロパティに値を設定すると、setterメソッドが呼び出され、_nameプロパティの値が変更されます。

データの検証

setterを使用することで、値が設定される前に検証を行うことができます。これにより、不正な値の設定を防ぐことができます。

let user = {
  _age: 25,
  set age(value) {
    if (value > 0 && value < 120) {
      this._age = value;
    } else {
      console.log('Invalid age');
    }
  }
};

user.age = 30; // Valid age
console.log(user._age); // 30
user.age = -5; // Invalid age
console.log(user._age); // 30

この例では、年齢が0から120の範囲内にあるかをチェックし、範囲外の場合には警告メッセージを表示します。

データの整形

setterを使って、設定される値を整形することも可能です。例えば、文字列を常に大文字に変換するsetterを作成することができます。

let book = {
  _title: '',
  set title(value) {
    this._title = value.toUpperCase();
  }
};

book.title = 'JavaScript Essentials';
console.log(book._title); // "JAVASCRIPT ESSENTIALS"

この例では、titleプロパティに設定される値が常に大文字に変換されます。

依存プロパティの更新

setterを使うことで、あるプロパティの変更が他のプロパティに影響を与える場合に、依存プロパティを自動的に更新することができます。

let rectangle = {
  _width: 10,
  _height: 20,
  set width(value) {
    this._width = value;
    this._area = this._width * this._height;
  },
  set height(value) {
    this._height = value;
    this._area = this._width * this._height;
  },
  get area() {
    return this._area;
  }
};

rectangle.width = 15;
console.log(rectangle.area); // 300
rectangle.height = 10;
console.log(rectangle.area); // 150

この例では、widthまたはheightプロパティが変更されると、自動的にareaプロパティも更新されます。

setterを使用することで、プロパティの値を設定する際に必要な検証や整形、依存関係の管理を行うことができます。これにより、オブジェクトのデータ管理がより堅牢で柔軟になります。

実例:シンプルなオブジェクト

getterとsetterの基本的な使い方を理解したところで、実際のシンプルなオブジェクトにこれらを適用してみましょう。この例では、Personオブジェクトを作成し、名前と年齢のプロパティに対してgetterとsetterを使用します。

Personオブジェクトの定義

以下に、Personオブジェクトの定義とgetterおよびsetterを使用した例を示します。

let Person = {
  _name: 'John Doe',
  _age: 30,

  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  },

  get age() {
    return this._age;
  },

  set age(value) {
    if (value > 0 && value < 120) {
      this._age = value;
    } else {
      console.log('Invalid age');
    }
  }
};

// 値の取得
console.log(Person.name); // "John Doe"
console.log(Person.age);  // 30

// 値の設定
Person.name = 'Jane Smith';
console.log(Person.name); // "Jane Smith"

Person.age = 25;
console.log(Person.age);  // 25

// 無効な値の設定
Person.name = '';
// "Name cannot be empty"
Person.age = -5;
// "Invalid age"

コードの説明

この例では、Personオブジェクトに_name_ageという内部プロパティを持たせ、それに対するgetterとsetterを定義しています。

  • nameプロパティのgetterは、内部プロパティ_nameの値を返します。
  • nameプロパティのsetterは、与えられた値が空文字列でないかをチェックし、条件を満たす場合に_nameを更新します。
  • ageプロパティのgetterは、内部プロパティ_ageの値を返します。
  • ageプロパティのsetterは、与えられた値が0から120の範囲内にあるかをチェックし、条件を満たす場合に_ageを更新します。

このようにして、Personオブジェクトに対する不正な操作を防ぎ、データの整合性を保つことができます。getterとsetterを使用することで、プロパティのアクセスと設定を安全かつ効率的に行う方法を実践的に学べます。

実例:高度なアクセス制御

シンプルなオブジェクトの例に続いて、より複雑なオブジェクトでの高度なアクセス制御について見ていきましょう。この例では、複数の関連プロパティを持つオブジェクトに対して、getterとsetterを使用して高度なロジックを適用します。

Productオブジェクトの定義

以下に、在庫数と価格を管理するProductオブジェクトの例を示します。このオブジェクトでは、在庫数が0になると価格を自動的に設定できなくするロジックを導入しています。

let Product = {
  _name: 'Sample Product',
  _price: 100,
  _stock: 50,

  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  },

  get price() {
    return this._price;
  },

  set price(value) {
    if (this._stock > 0) {
      if (value > 0) {
        this._price = value;
      } else {
        console.log('Price must be positive');
      }
    } else {
      console.log('Cannot set price when stock is zero');
    }
  },

  get stock() {
    return this._stock;
  },

  set stock(value) {
    if (value >= 0) {
      this._stock = value;
    } else {
      console.log('Stock cannot be negative');
    }
  }
};

// 値の取得
console.log(Product.name);  // "Sample Product"
console.log(Product.price); // 100
console.log(Product.stock); // 50

// 値の設定
Product.name = 'New Product';
console.log(Product.name); // "New Product"

Product.price = 150;
console.log(Product.price); // 150

Product.stock = 0;
console.log(Product.stock); // 0

// 無効な値の設定
Product.price = 200;
// "Cannot set price when stock is zero"
console.log(Product.price); // 150
Product.stock = -10;
// "Stock cannot be negative"

コードの説明

この例では、Productオブジェクトに_name_price、および_stockという内部プロパティを持たせ、それぞれに対するgetterとsetterを定義しています。

  • nameプロパティのgetterとsetterは、シンプルな検証を行い、空の名前を設定できないようにしています。
  • priceプロパティのgetterとsetterは、在庫がある場合のみ価格を設定できるようにし、在庫が0の場合には価格を変更できないようにしています。また、価格は正の値のみ許可されます。
  • stockプロパティのgetterとsetterは、在庫が負の値にならないようにチェックしています。

このようにして、Productオブジェクトに対する操作を厳密に制御し、データの整合性とビジネスロジックを確保しています。getterとsetterを使うことで、オブジェクトのプロパティに対する高度なアクセス制御を実現し、プログラムの堅牢性を高めることができます。

パフォーマンスへの影響

getterとsetterを使用することで得られるメリットは多いですが、その使用がパフォーマンスに与える影響についても理解しておくことが重要です。ここでは、getterとsetterのパフォーマンスに関する考慮点を解説します。

メソッド呼び出しのオーバーヘッド

getterとsetterは通常のプロパティアクセスに比べて、メソッド呼び出しのオーバーヘッドが発生します。特に大量のデータアクセスが頻繁に行われる場合、このオーバーヘッドがパフォーマンスに影響を与える可能性があります。

let obj = {
  _value: 0,
  get value() {
    return this._value;
  },
  set value(val) {
    this._value = val;
  }
};

// パフォーマンス測定例
console.time('Direct Access');
for (let i = 0; i < 1000000; i++) {
  obj._value = i;
  let temp = obj._value;
}
console.timeEnd('Direct Access');

console.time('Getter/Setter Access');
for (let i = 0; i < 1000000; i++) {
  obj.value = i;
  let temp = obj.value;
}
console.timeEnd('Getter/Setter Access');

この例では、直接プロパティにアクセスする場合とgetter/setterを経由する場合のパフォーマンスを比較しています。大量のアクセスが発生する場合、getter/setterのオーバーヘッドが明確になるでしょう。

最適化のポイント

パフォーマンスへの影響を最小限に抑えるためには、以下のポイントに注意する必要があります。

不要なgetter/setterの使用を避ける

すべてのプロパティに対してgetter/setterを使用するのではなく、本当に必要な箇所にのみ使用することで、オーバーヘッドを減らせます。

単純なgetter/setterを使用する

getter/setterの中に複雑なロジックを含めると、呼び出しごとのコストが増加します。可能な限りシンプルなロジックを保つようにしましょう。

キャッシングの活用

計算結果をキャッシュすることで、頻繁に呼び出されるgetterのオーバーヘッドを減らすことができます。

let rectangle = {
  _width: 10,
  _height: 20,
  _area: null,
  get area() {
    if (this._area === null) {
      this._area = this._width * this._height;
    }
    return this._area;
  },
  set width(value) {
    this._width = value;
    this._area = null;
  },
  set height(value) {
    this._height = value;
    this._area = null;
  }
};

console.log(rectangle.area); // 200
rectangle.width = 15;
console.log(rectangle.area); // 300

この例では、面積の計算結果をキャッシュすることで、不要な計算を避けています。

実用上のパフォーマンス評価

実際のアプリケーションでgetterとsetterを使用する場合、パフォーマンスへの影響はケースバイケースです。小規模なスクリプトや軽量な処理ではほとんど問題にならない一方、大規模なデータ操作やリアルタイム性が求められるアプリケーションでは影響が顕著になる可能性があります。

パフォーマンスが問題となる場合、プロファイリングツールを使用して実際の影響を測定し、必要に応じて最適化することが重要です。getterとsetterの利便性とパフォーマンスのバランスを見極めることで、効果的なコードを書くことができます。

デバッグの方法

getterとsetterを使用するコードは、その特性上、デバッグが難しい場合があります。ここでは、getterとsetterを使用したコードのデバッグ方法について解説します。

コンソールログの活用

getterとsetterの内部でconsole.logを使用することで、プロパティへのアクセスや変更が行われた際の情報を取得できます。これにより、実行時の動作を確認しやすくなります。

let user = {
  _name: 'Alice',
  get name() {
    console.log('Getting name');
    return this._name;
  },
  set name(value) {
    console.log('Setting name to', value);
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  }
};

user.name = 'Bob'; // "Setting name to Bob"
console.log(user.name); // "Getting name", "Bob"

デバッガの使用

JavaScriptのデバッガを使用すると、getterとsetterを含むコードの実行をステップごとに追跡できます。debuggerステートメントをgetterやsetterの内部に追加すると、その部分で実行が停止し、変数の状態を確認できます。

let product = {
  _price: 50,
  get price() {
    debugger; // ブレークポイントを設定
    return this._price;
  },
  set price(value) {
    debugger; // ブレークポイントを設定
    if (value > 0) {
      this._price = value;
    } else {
      console.log('Invalid price');
    }
  }
};

product.price = 75; // ブレークポイントが発動
console.log(product.price); // ブレークポイントが発動

プロキシの活用

プロキシを使用してオブジェクトの操作を監視し、ログを取得する方法もあります。プロキシを使用すると、getterやsetterの外部でオブジェクトの操作をキャプチャできます。

let handler = {
  get(target, property) {
    console.log(`Getting ${property}`);
    return target[property];
  },
  set(target, property, value) {
    console.log(`Setting ${property} to ${value}`);
    target[property] = value;
    return true;
  }
};

let person = {
  _name: 'Charlie',
  _age: 28,
  get name() {
    return this._name;
  },
  set name(value) {
    this._name = value;
  },
  get age() {
    return this._age;
  },
  set age(value) {
    this._age = value;
  }
};

let proxyPerson = new Proxy(person, handler);

proxyPerson.name = 'David'; // "Setting name to David"
console.log(proxyPerson.name); // "Getting name", "David"

ユニットテストの作成

getterとsetterを含むコードのユニットテストを作成することで、動作を自動的に検証できます。ユニットテストを使用することで、特定の条件下での動作を確実に確認でき、バグの早期発見に役立ちます。

const assert = require('assert');

let car = {
  _speed: 0,
  get speed() {
    return this._speed;
  },
  set speed(value) {
    if (value >= 0) {
      this._speed = value;
    } else {
      console.log('Speed cannot be negative');
    }
  }
};

car.speed = 50;
assert.strictEqual(car.speed, 50, 'Speed should be 50');

car.speed = -10;
assert.strictEqual(car.speed, 50, 'Speed should still be 50 (invalid update)');

このように、getterとsetterを使用したコードのデバッグには、コンソールログ、デバッガ、プロキシ、ユニットテストなどのさまざまな方法があります。適切な方法を選択してデバッグを行うことで、コードの信頼性を向上させることができます。

応用例:フォームのバリデーション

getterとsetterは、フォームのバリデーションに非常に有効です。ユーザーが入力したデータを検証し、適切な形式に整えるためのロジックを容易に組み込むことができます。ここでは、実際のフォームバリデーションにgetterとsetterを使用する例を紹介します。

フォームオブジェクトの定義

以下に、ユーザー登録フォームを例として、名前とメールアドレスのバリデーションを行うオブジェクトを定義します。

let registrationForm = {
  _name: '',
  _email: '',

  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  },

  get email() {
    return this._email;
  },

  set email(value) {
    // 簡易的なメールアドレスの正規表現
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (emailPattern.test(value)) {
      this._email = value;
    } else {
      console.log('Invalid email address');
    }
  }
};

// ユーザー入力のシミュレーション
registrationForm.name = 'Alice';
registrationForm.email = 'alice@example.com';

console.log(registrationForm.name);  // "Alice"
console.log(registrationForm.email); // "alice@example.com"

// 無効な入力のシミュレーション
registrationForm.name = '';            // "Name cannot be empty"
registrationForm.email = 'alice@com';  // "Invalid email address"

コードの説明

この例では、registrationFormオブジェクトに_name_emailという内部プロパティを持たせ、それぞれに対するgetterとsetterを定義しています。

  • nameプロパティのsetterは、空の名前が設定されないように検証します。
  • emailプロパティのsetterは、正規表現を使用してメールアドレスの形式を検証します。

これにより、ユーザーが入力したデータが適切な形式であることを保証し、不正なデータの入力を防ぎます。

リアルタイムバリデーションの実装

getterとsetterを使用して、リアルタイムでフォームのバリデーションを行うことも可能です。以下に、HTMLフォームと連携した例を示します。

<!DOCTYPE html>
<html>
<head>
  <title>Form Validation</title>
  <script>
    document.addEventListener('DOMContentLoaded', () => {
      let form = {
        _name: '',
        _email: '',

        get name() {
          return this._name;
        },

        set name(value) {
          if (value.length > 0) {
            this._name = value;
            document.getElementById('nameError').textContent = '';
          } else {
            document.getElementById('nameError').textContent = 'Name cannot be empty';
          }
        },

        get email() {
          return this._email;
        },

        set email(value) {
          const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
          if (emailPattern.test(value)) {
            this._email = value;
            document.getElementById('emailError').textContent = '';
          } else {
            document.getElementById('emailError').textContent = 'Invalid email address';
          }
        }
      };

      document.getElementById('name').addEventListener('input', (event) => {
        form.name = event.target.value;
      });

      document.getElementById('email').addEventListener('input', (event) => {
        form.email = event.target.value;
      });
    });
  </script>
</head>
<body>
  <form>
    <label for="name">Name:</label>
    <input type="text" id="name">
    <span id="nameError" style="color: red;"></span><br><br>

    <label for="email">Email:</label>
    <input type="text" id="email">
    <span id="emailError" style="color: red;"></span><br><br>
  </form>
</body>
</html>

コードの説明

このHTMLとJavaScriptの例では、以下の機能を実現しています。

  • ユーザーが入力フィールドに値を入力すると、対応するsetterが呼び出され、入力値が検証されます。
  • 検証結果に応じて、エラーメッセージがリアルタイムで表示されます。

getterとsetterを使用することで、フォームのバリデーションロジックを分かりやすく整理し、ユーザーにとって使いやすいインターフェースを提供できます。これにより、入力データの整合性とユーザーエクスペリエンスを向上させることができます。

演習問題

ここでは、getterとsetterを使用して学んだ内容を実践するための演習問題を提供します。実際に手を動かしてコードを書いてみることで、理解を深めましょう。

演習問題1:製品の在庫管理

製品の在庫数と価格を管理するオブジェクトを作成し、getterとsetterを使用して在庫数が0の時に価格を変更できないようにします。また、在庫数が負の値にならないように検証します。

let Product = {
  _name: 'Sample Product',
  _price: 100,
  _stock: 50,

  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  },

  get price() {
    return this._price;
  },

  set price(value) {
    if (this._stock > 0) {
      if (value > 0) {
        this._price = value;
      } else {
        console.log('Price must be positive');
      }
    } else {
      console.log('Cannot set price when stock is zero');
    }
  },

  get stock() {
    return this._stock;
  },

  set stock(value) {
    if (value >= 0) {
      this._stock = value;
    } else {
      console.log('Stock cannot be negative');
    }
  }
};

// 演習
// 1. Productオブジェクトのnameプロパティを 'Updated Product' に変更する
// 2. Productオブジェクトのpriceプロパティを 200 に変更する
// 3. Productオブジェクトのstockプロパティを 0 に変更する
// 4. Productオブジェクトのpriceプロパティを 300 に変更しようとして、失敗させる

演習問題2:ユーザー情報のバリデーション

ユーザーの名前、年齢、およびメールアドレスを管理するオブジェクトを作成し、getterとsetterを使用してデータのバリデーションを行います。

let User = {
  _name: '',
  _age: 0,
  _email: '',

  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length > 0) {
      this._name = value;
    } else {
      console.log('Name cannot be empty');
    }
  },

  get age() {
    return this._age;
  },

  set age(value) {
    if (value > 0 && value <= 120) {
      this._age = value;
    } else {
      console.log('Invalid age');
    }
  },

  get email() {
    return this._email;
  },

  set email(value) {
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (emailPattern.test(value)) {
      this._email = value;
    } else {
      console.log('Invalid email address');
    }
  }
};

// 演習
// 1. Userオブジェクトのnameプロパティを 'John Doe' に変更する
// 2. Userオブジェクトのageプロパティを 25 に変更する
// 3. Userオブジェクトのemailプロパティを 'john.doe@example.com' に変更する
// 4. Userオブジェクトのemailプロパティを 'invalid-email' に変更しようとして、失敗させる

演習問題3:銀行口座の管理

銀行口座の残高を管理するオブジェクトを作成し、getterとsetterを使用して残高が負の値にならないようにします。また、預入と引出のメソッドを追加し、適切に残高を管理します。

let BankAccount = {
  _balance: 0,

  get balance() {
    return this._balance;
  },

  set balance(value) {
    if (value >= 0) {
      this._balance = value;
    } else {
      console.log('Balance cannot be negative');
    }
  },

  deposit(amount) {
    if (amount > 0) {
      this.balance += amount;
    } else {
      console.log('Deposit amount must be positive');
    }
  },

  withdraw(amount) {
    if (amount > 0 && this.balance >= amount) {
      this.balance -= amount;
    } else {
      console.log('Invalid withdraw amount');
    }
  }
};

// 演習
// 1. BankAccountオブジェクトのdepositメソッドを使って1000を預け入れる
// 2. BankAccountオブジェクトのwithdrawメソッドを使って500を引き出す
// 3. BankAccountオブジェクトのwithdrawメソッドを使って10000を引き出そうとして、失敗させる

これらの演習を通じて、getterとsetterの使い方を実践的に学び、オブジェクトのプロパティに対するアクセス制御とデータのバリデーションを効果的に行う方法を習得してください。

まとめ

本記事では、JavaScriptにおけるgetterとsetterを使用したアクセス制御について詳細に解説しました。getterとsetterの基本的な使い方から始まり、シンプルなオブジェクトと高度なオブジェクトの実例、パフォーマンスへの影響、デバッグ方法、そして応用例としてフォームのバリデーションを紹介しました。

getterとsetterを使用することで、オブジェクトのプロパティへのアクセスを柔軟に制御し、データの整合性や安全性を保つことができます。また、これらを用いたアクセス制御は、コードの可読性や保守性を向上させるための重要な手段です。パフォーマンスに関しては、適切な場面での使用と最適化を行うことで、オーバーヘッドを最小限に抑えることが可能です。

最後に、実際の使用例と演習問題を通じて、getterとsetterの実践的な応用方法を学びました。これらの知識を活用して、より堅牢で効率的なJavaScriptプログラムを作成することができるでしょう。今後も実践を重ね、さらに深い理解を目指してください。

コメント

コメントする

目次