JavaScriptにおけるクラスの追加機能

JavaScriptにおけるクラスの追加機能

この記事ではJavaScriptにおけるクラスの追加機能について説明します。

YouTube Video

JavaScriptにおけるクラスの追加機能

JavaScriptにおけるプライベートプロパティ

JavaScriptにおいて、プライベートプロパティはオブジェクトやクラスの内部でのみアクセス可能なプロパティです。これは、外部のコードから直接変更や参照ができないようにし、カプセル化を提供することで、より安全で堅牢なコード設計を可能にします。

2020年に導入されたECMAScript 2020(ES11)では、クラス内でプライベートフィールドを定義するために#を使用する方法が導入されました。これにより、従来のJavaScriptのプライベートな慣習的表現(例えば、アンダースコアで始まる変数名など)を置き換えるより明確な方法が提供されました。

プライベートプロパティの使い方

クラスにおけるプライベートプロパティの定義

プライベートフィールドは、#で始まる名前を使って定義します。このフィールドは、そのクラスのインスタンスやサブクラスからは直接アクセスできません。

 1class Person {
 2    // Define private property
 3    #name;
 4
 5    constructor(name) {
 6        this.#name = name;
 7    }
 8
 9    // Method to access the private property
10    getName() {
11        return this.#name;
12    }
13
14    // Method to change the private property
15    setName(newName) {
16        this.#name = newName;
17    }
18}
19
20const john = new Person("John");
21console.log(john.getName()); // John

上記のコードでは、#nameはプライベートプロパティであり、Personクラスの外部からは直接アクセスできません。getNameおよびsetNameメソッドを通じてのみ、名前にアクセスや変更が可能です。

1// Cannot access private property directly
2console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class

プライベートメソッドの定義

プライベートプロパティと同様に、プライベートメソッドも#で始まる名前を使って定義します。プライベートメソッドは、そのクラスの内部からのみ呼び出すことができます。

 1class Counter {
 2    #count = 0;
 3
 4    increment() {
 5        this.#count++;
 6        this.#logCount(); // Calling private method
 7    }
 8
 9    // Private method
10    #logCount() {
11        console.log(`Current count: ${this.#count}`);
12    }
13}
14
15const counter = new Counter();
16counter.increment(); // Current count: 1

ここでは、#logCountがプライベートメソッドとして定義されており、クラスの外部からはアクセスできません。このメソッドはクラス内部でのみ使用されます。

1// Cannot access private method directly
2counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class

プライベートプロパティの利点と注意点

利点

  • カプセル化:内部状態を外部から隠蔽し、データの一貫性を保てます。
  • セキュリティ:外部のコードからプロパティが意図せず変更されることを防げます。
  • コードの保守性向上:オブジェクトやクラスの実装を隠蔽し、外部に公開するインターフェースを明確にできます。

注意点

  • プライベートフィールドはクラスの外部から完全に隠されるため、テストやデバッグが難しくなることがあります。そのため、設計段階でしっかりとテスト可能なAPIを提供することが重要です。
  • プライベートフィールドは、インスタンスごとに異なるため、プロトタイプベースの特性を持つJavaScriptの他の部分とは異なる挙動をすることがあります。

従来のプライベートプロパティの疑似的な実装

#によるプライベートフィールドの導入以前は、JavaScriptにはプライベートプロパティの公式な構文がありませんでした。そのため、従来は次のような方法で疑似的にプライベートを実装していました。

アンダースコアによる慣習

開発者は、変数名の先頭にアンダースコアを付けることで、慣習的に「プライベート」を示していました。

 1class Car {
 2    constructor(brand) {
 3        this._brand = brand; // Using an underscore to indicate private
 4    }
 5
 6    getBrand() {
 7        return this._brand;
 8    }
 9}
10
11const car = new Car("Toyota");
12console.log(car.getBrand()); // Toyota
13console.log(car._brand); // Toyota (Accessible from outside)

この方法はあくまで「慣習」であり、実際には外部からアクセス可能です。

クロージャを使ったプライベートプロパティの実装

関数スコープを利用したクロージャを使うことで、プライベートプロパティを実現することも可能です。

 1function createPerson(name) {
 2    let _name = name; // Private variable within function scope
 3
 4    return {
 5        getName: function() {
 6            return _name;
 7        },
 8        setName: function(newName) {
 9            _name = newName;
10        }
11    };
12}
13
14const person = createPerson("Alice");
15console.log(person.getName()); // Alice
16person.setName("Bob");
17console.log(person.getName()); // Bob
18
19// Cannot access directly from outside
20console.log(person._name); // undefined

この方法では、変数_nameは関数のスコープ内に閉じ込められており、外部から直接アクセスすることはできません。

まとめ

JavaScriptにおけるプライベートプロパティは、クラスやオブジェクトの設計においてカプセル化を提供し、データを安全に保護するために非常に有効です。ES2020で導入された#記法によるプライベートフィールドは、従来の慣習やクロージャを使ったプライバシー管理よりも明確で安全な手段です。

JavaScriptにおけるオプショナルチェーン

オプショナルチェーンは、JavaScriptで深くネストされたオブジェクトのプロパティにアクセスする際に非常に便利な構文です。特定のプロパティが存在するかどうかを逐一チェックせずに安全にアクセスできるため、コードの可読性と保守性が向上します。

オプショナルチェーンの基本構文

オプショナルチェーンは、プロパティアクセスに使う.やブラケット記法の前に ? を付けることで使用できます。この記法を使用すると、途中のプロパティが null または undefined の場合に undefined を返し、エラーを発生させずに安全に処理を続けることができます。

例:

 1const user = {
 2    name: 'John',
 3    address: {
 4        street: '123 Main St',
 5        city: 'New York'
 6    }
 7};
 8
 9// Without using optional chaining
10const city = user && user.address && user.address.city;
11console.log(city);  // New York
12
13// Using optional chaining
14const cityWithOptionalChaining = user?.address?.city;
15console.log(cityWithOptionalChaining);  // New York

この例では、user オブジェクトの address とその city プロパティにアクセスしています。オプショナルチェーンを使わない場合は、存在チェックを何度も行う必要がありますが、オプショナルチェーンを使うと一度の記述で安全にアクセスできます。

配列や関数へのオプショナルチェーンの使用

オプショナルチェーンはオブジェクトのプロパティだけでなく、配列の要素や関数の呼び出しにも適用できます。

配列での例:

1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser);  // undefined
  • このように、オプショナルチェーンを用いて配列の要素にアクセスすることもできます。

関数での例:

 1const user = {
 2    greet: function() {
 3        return 'Hello!';
 4    }
 5};
 6
 7// Call the function only if greet exists
 8const greeting = user.greet?.();
 9console.log(greeting);  // Hello!
10
11// Return undefined if greet does not exist
12const nonExistentGreeting = user.nonExistentMethod?.();
13console.log(nonExistentGreeting);  // undefined
  • この例のように関数の呼び出しにも適用できます。

オプショナルチェーンとデフォルト値の組み合わせ

オプショナルチェーンを使用する際、プロパティが存在しない場合のデフォルト値を指定するために、論理OR演算子 (||) やNull合体演算子 (??) を併用することがよくあります。

例:

 1const user = {
 2    name: 'John',
 3    address: {
 4        city: 'New York'
 5    }
 6};
 7
 8// Set a default value for a non-existent property
 9const state = user?.address?.state || 'Unknown';
10console.log(state);  // Unknown
11
12// Example using the nullish coalescing operator
13const zipCode = user?.address?.zipCode ?? '00000';
14console.log(zipCode);  // 00000

論理OR演算子は、false0'' なども「偽」として扱いますが、Null合体演算子は null または undefined の場合にのみデフォルト値を使用します。

オプショナルチェーンの利点

  • ネストされたオブジェクトに安全にアクセス: オプショナルチェーンを使うことで、存在チェックを明示的に行う必要がなくなり、コードが簡潔になります。
  • エラーの回避: プロパティが null または undefined の場合でも、実行時エラーを防ぐことができます。
  • 読みやすさと保守性の向上: 特に多くのネストされたオブジェクトを扱う場合、コードの可読性が大幅に向上します。

オプショナルチェーンの注意点

  • オプショナルチェーンを頻繁に使いすぎると、データ構造の設計が複雑すぎることの兆候である場合があります。シンプルなデータモデルを心がけるべきです。
  • 一部の古いブラウザやJavaScriptエンジンではサポートされていないため、ポリフィルやトランスパイラを使用する必要がある場合があります。

結論

オプショナルチェーンは、JavaScriptでのネストされたオブジェクトのプロパティや関数への安全なアクセスを簡素化する非常に強力な機能です。深くネストされたデータ構造にアクセスする場面では特に有効であり、エラーの防止やコードの可読性向上に貢献します。

YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。

YouTube Video