【決定版】JavaScript, TypeScript, ECMAScript 5 でアクセサーを使いこなすためのチュートリアル
JavaScript、TypeScript、ECMAScript 5におけるアクセサー
アクセサーのしくみ
アクセサーは、getterとsetterの2つのメソッドで構成されます。
- getter: プロパティの値を取得するメソッドです。通常のプロパティ参照のように
object.propertyName
と記述するだけで呼び出されます。
アクセサーを使用する利点は以下の通りです。
- プロパティへのアクセスを制御: アクセサーを使用することで、プロパティへの読み書きアクセスを制御できます。例えば、値の変更を検証したり、変更履歴を記録したりすることができます。
- カプセル化の強化: アクセサーを内部メソッドとして実装することで、オブジェクト内部の実装を隠蔽し、カプセル化を強化することができます。
- コードの可読性向上: アクセサーを使用することで、プロパティの読み書き処理をより分かりやすく記述することができます。
以下の例は、fullName
プロパティの getter と setter を定義した JavaScript のコードです。
class Person {
constructor(firstName, lastName) {
this._firstName = firstName;
this._lastName = lastName;
}
get fullName() {
return `${this._firstName} ${this._lastName}`;
}
set fullName(value) {
const parts = value.split(' ');
this._firstName = parts[0];
this._lastName = parts[1];
}
}
const person = new Person('John', 'Doe');
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
この例では、fullName
プロパティは単なる文字列ではなく、firstName
と lastName
プロパティを結合した値を返すように実装されています。また、fullName
プロパティに値を設定する場合、_firstName
と _lastName
プロパティを個別に更新するようにしています。
TypeScript では、アクセサーに型注釈を追加することで、型安全性を強化することができます。
class Person {
private _firstName: string;
private _lastName: string;
constructor(firstName: string, lastName: string) {
this._firstName = firstName;
this._lastName = lastName;
}
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
set fullName(value: string) {
const parts = value.split(' ');
this._firstName = parts[0];
this._lastName = parts[1];
}
}
const person: Person = new Person('John', 'Doe');
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
この例では、fullName
プロパティの getter と setter に型注釈を追加することで、返値と引数の型を明確に指定しています。
ECMAScript 5 では、Object.defineProperty()
関数を使用して、アクセサーを定義できます。
const person = {};
Object.defineProperty(person, 'fullName', {
get: function() {
return `${this.firstName} ${this.lastName}`;
},
set: function(value) {
const parts = value.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
}
});
person.firstName = 'John';
person.lastName = 'Doe';
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
この例は、ECMAScript 5 で fullName
プロパティにアクセサーを定義する方法を示しています。
アクセサーは、JavaScript、TypeScript、および ECMAScript 5 で利用できる強力な機能です。プロパティへのアクセスを制御し、カプセル化を強化し、コードの可読性を向上させる
JavaScript
class Person {
constructor(firstName, lastName) {
this._firstName = firstName;
this._lastName = lastName;
}
get fullName() {
return `${this._firstName} ${this._lastName}`;
}
set fullName(value) {
const parts = value.split(' ');
this._firstName = parts[0];
this._lastName = parts[1];
}
}
const person = new Person('John', 'Doe');
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
TypeScript
class Person {
private _firstName: string;
private _lastName: string;
constructor(firstName: string, lastName: string) {
this._firstName = firstName;
this._lastName = lastName;
}
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
set fullName(value: string) {
const parts = value.split(' ');
this._firstName = parts[0];
this._lastName = parts[1];
}
}
const person: Person = new Person('John', 'Doe');
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
ECMAScript 5
const person = {};
Object.defineProperty(person, 'fullName', {
get: function() {
return `${this.firstName} ${this.lastName}`;
},
set: function(value) {
const parts = value.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
}
});
person.firstName = 'John';
person.lastName = 'Doe';
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
getter
メソッドは、fullName
プロパティの値を取得します。
アクセサーを使用することで、以下の利点が得られます。
- プロパティへのアクセスを制御することができます。例えば、
fullName
プロパティの値を変更する前に、検証処理を実行することができます。 - カプセル化を強化することができます。
_firstName
と_lastName
プロパティを外部から直接参照できなくすることで、オブジェクト内部の実装を隠蔽することができます。
このサンプルコードは、あくまでもアクセサーの基本的な使用方法を示したものです。実際の開発では、状況に応じて様々な応用が可能です。
アクセサー以外の代替方法
プロパティ修飾子を使用して、プロパティのアクセス権限を制御することができます。主な修飾子は以下の通りです。
public
: プロパティを公開します。private
: プロパティを非公開にし、クラス内でのみアクセスできるようにします。
class Person {
#firstName = 'John'; // private プロパティ
lastName = 'Doe'; // public プロパティ
get fullName() {
return `${this.#firstName} ${this.lastName}`;
}
set fullName(value) {
const parts = value.split(' ');
this.#firstName = parts[0];
this.lastName = parts[1];
}
}
この例では、#firstName
プロパティは private
修飾子を使用して非公開に設定されています。一方、lastName
プロパティは public
修飾子を使用して公開に設定されています。
クロージャを使用して、プロパティの値をカプセル化することができます。
function Person(firstName, lastName) {
const _firstName = firstName;
const _lastName = lastName;
return {
get fullName() {
return `${_firstName} ${_lastName}`;
},
set fullName(value) {
const parts = value.split(' ');
_firstName = parts[0];
_lastName = parts[1];
}
};
}
const person = Person('John', 'Doe');
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
この例では、クロージャを使用して _firstName
と _lastName
プロパティをカプセル化しています。これらのプロパティは、外部から直接参照することはできませんが、fullName
プロパティの getter と setter メソッドを通じてアクセスすることができます。
シンボルを使用して、ユニークなプロパティ名を作成することができます。
const firstNameSymbol = Symbol('firstName');
const lastNameSymbol = Symbol('lastName');
class Person {
constructor(firstName, lastName) {
this[firstNameSymbol] = firstName;
this[lastNameSymbol] = lastName;
}
get fullName() {
return `${this[firstNameSymbol]} ${this[lastNameSymbol]}`;
}
set fullName(value) {
const parts = value.split(' ');
this[firstNameSymbol] = parts[0];
this[lastNameSymbol] = parts[1];
}
}
const person = new Person('John', 'Doe');
console.log(person.fullName); // John Doe
person.fullName = 'Jane Smith';
console.log(person.fullName); // Jane Smith
この例では、シンボルを使用して firstName
と lastName
プロパティ名を定義しています。これらのプロパティ名は、外部から推測することが難しく、意図しないプロパティの書き換えを防ぐことができます。
アクセサーと代替方法の比較
方法 | 利点 | 欠点 |
---|---|---|
アクセサー | 構文的に簡潔 | ブラウザサポートに依存する |
プロパティ修飾子 | シンプルで分かりやすい | 継承関係でのみ有効 |
クロージャ | カプセル化に優れている | 冗長なコード記述が必要 |
シンボル | ユニークなプロパティ名を定義できる | シンボルに慣れていないと理解しにくい |
アクセサーは、プロパティの読み書きを制御する強力な機能ですが、ブラウザサポートの状況によっては代替方法を検討する必要があります。状況に応じて適切な方法を選択することが重要です。
上記以外にも、様々な代替方法が存在します。詳細は、以下の資料を参照してください。
javascript typescript ecmascript-5