MochiuWiki : SUSE, EC, PCB
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
JavaScriptの基礎 - クラスのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
JavaScriptの基礎 - クラス
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == ES2015 (ES6) で導入された <code>class</code> 構文は、JavaScriptにおけるクラスベースのオブジェクト生成を簡潔に記述するためのシンタックスシュガーである。<br> JavaScriptの内部的なオブジェクト機構はプロトタイプベースであり、class構文はその仕組みをより直感的な形式で表現するためのものである。<br> <br> クラスは <code>constructor</code> メソッドによるインスタンス初期化、インスタンスメソッド、ゲッター / セッターといった基本機能を備えている。<br> <br> ES2022では、クラスボディでのパブリックフィールド宣言およびプライベートメンバー (<code>#</code> 記法) が正式仕様として標準化された。<br> また、<code>static</code> キーワードにより、インスタンスではなくクラス自体に属する静的メソッドおよび静的プロパティを定義できる。<br> <br> クラス宣言は関数宣言とは異なりホイスティング後もTDZ (Temporal Dead Zone) に入るため、定義より前にクラスを使用するとエラーになる点に注意が必要である。<br> クラスボディは自動的にstrictモードで実行される。<br> <br> 現代のReact開発では関数コンポーネントとHooksが主流であるが、ErrorBoundaryのような特定の機能にはクラスコンポーネントが今なお必須である。<br> <br> クラスの継承 (<code>extends</code> / <code>super</code>) やプロトタイプチェーンの詳細については、[[JavaScriptの基礎 - 継承とプロトタイプ]]のページを参照すること。<br> <br><br> == クラスの基本構文 == クラスの基本的な宣言方法とコンストラクタ、メソッドの定義について以下に示す。<br> <br> ==== クラスの宣言 ==== <code>class</code> キーワードを使用してクラスを宣言する。<br> クラスボディ (<code>{ }</code> の内部) には、コンストラクタやメソッドを定義する。<br> <br> クラス宣言の主な特性を以下に示す。<br> <br> <center> {| class="wikitable" |+ class宣言の特性 ! 項目 !! 説明 |- | rowspan="2" | ホイスティングの挙動 || 関数宣言とは異なり、<code>class</code> 宣言はホイスティングされるが、<br>TDZ (Temporal Dead Zone) に入る。 |- | 定義より前にクラスを使用すると <u>ReferenceError</u> が発生する。 |- | strictモード || クラスボディは自動的にstrictモードで実行される。<br><code>"use strict"</code> を明示する必要はない。 |} </center> <br> 基本的なクラス宣言の例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> // クラス宣言 class Person { constructor(name, age) { this.name = name; // インスタンスのプロパティを初期化する this.age = age; } // インスタンスメソッド greet() { console.log("こんにちは、" + this.name + "です。年齢は" + this.age + "歳です。"); } } const taro = new Person("太郎", 25); taro.greet(); // "こんにちは、太郎です。年齢は25歳です。" </syntaxhighlight> <br> ホイスティングの挙動の例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> // クラスを定義より前に使用すると ReferenceError が発生する const p = new Person("太郎", 25); // ReferenceError: Cannot access 'Person' before initialization class Person { constructor(name, age) { this.name = name; this.age = age; } } </syntaxhighlight> <br> ==== コンストラクタ ==== <code>constructor</code> メソッドは、<code>new</code> 演算子でクラスのインスタンスを生成する際に自動的に呼び出される特別なメソッドである。<br> インスタンスのプロパティの初期化等、オブジェクト生成時の処理を記述する。<br> <br> 下表に、コンストラクタに関する主な仕様を示す。<br> <br> <center> {| class="wikitable" |+ constructorの仕様 ! 項目 !! 説明 |- | new演算子の必須 || <code>new</code> 演算子を使用せずにクラスを呼び出すと <u>TypeError</u> が発生する。 |- | rowspan="2" | デフォルトコンストラクタ || <code>constructor</code> を省略した場合、<br>空のデフォルトコンストラクタが自動的に挿入される。 |- | 継承クラスでコンストラクタを省略した場合は、<br><code>super(...args)</code> を呼び出すコンストラクタが自動挿入される。 |} </center> <br> コンストラクタの使用例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> class Car { constructor(make, model, year) { this.make = make; this.model = model; this.year = year; this.speed = 0; // 初期値を設定する } accelerate(amount) { this.speed += amount; console.log(this.make + " " + this.model + " の速度: " + this.speed + " km/h"); } brake(amount) { this.speed = Math.max(0, this.speed - amount); console.log(this.make + " " + this.model + " の速度: " + this.speed + " km/h"); } } const car = new Car("Toyota", "Prius", 2023); car.accelerate(60); // "Toyota Prius の速度: 60 km/h" car.brake(20); // "Toyota Prius の速度: 40 km/h" // new無しで呼び出すとTypeErrorが発生する // const car2 = Car("Toyota", "Prius", 2023); // TypeError: Class constructor Car cannot be invoked without 'new' </syntaxhighlight> <br> ==== メソッドの定義 ==== クラスで定義したインスタンスメソッドは、クラスのプロトタイプオブジェクトに追加される。<br> これにより、全インスタンスで同一のメソッドが共有される。<br> <br> ゲッター (<code>get</code>) と セッター (<code>set</code>) を使用することにより、プロパティへのアクセスに処理を挟むことができる。<br> ゲッターは計算プロパティやバリデーションに、セッターは値の検証や変換に活用される。<br> <br> getter / setterを使用したクラスの例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> class Circle { constructor(radius) { // セッターを経由してバリデーションを適用する this.radius = radius; } // セッター : radiusに代入する際に呼び出される set radius(value) { if (value < 0) { throw new Error("半径は0以上の値を指定してください"); } this._radius = value; } // ゲッター : radiusを参照する際に呼び出される get radius() { return this._radius; } // 計算プロパティとしてのゲッター (面積を都度計算する) get area() { return Math.PI * this._radius ** 2; } // 計算プロパティとしてのゲッター (円周を都度計算する) get circumference() { return 2 * Math.PI * this._radius; } } const c = new Circle(5); console.log(c.radius); // 5 console.log(c.area.toFixed(2)); // "78.54" c.radius = 10; console.log(c.area.toFixed(2)); // "314.16" // c.radius = -1; // Error : 半径は0以上の値を指定してください </syntaxhighlight> <br> 下表に、メソッドの種類と用途の比較を示す。<br> <br> <center> {| class="wikitable" |+ メソッドの種類比較 ! 種類 !! 構文 !! 呼び出し方 !! 用途 |- | インスタンスメソッド || <code>methodName() { ... }</code> || <code>instance.methodName()</code> || インスタンスに対する操作 |- | ゲッター || <code>get propName() { ... }</code> || <code>instance.propName</code> || 計算プロパティ、値の読み取り |- | セッター || <code>set propName(v) { ... }</code> || <code>instance.propName = value</code> || 値の検証、加工して保存 |} </center> <br><br> == フィールド宣言 == ES2022で正式仕様化されたクラスフィールド宣言を使用すると、<code>constructor</code> 外のクラスボディにフィールドを直接定義できる。<br> <br> フィールドはプロトタイプではなく各インスタンスのプロパティとして設定される。<br> <br> ==== パブリックフィールド ==== パブリックフィールドは、クラスボディの先頭でフィールド名と初期値を宣言することで定義する。<br> <br> <code>constructor</code> 内での <u>this.propName = value</u> の記述が不要になり、クラスの構造をより明確に表現できる。<br> <br> 下表に、パブリックフィールドの特性を示す。<br> <br> <center> {| class="wikitable" |+ パブリックフィールドの特性 ! 特性 !! 説明 |- | インスタンスプロパティとして設定される || フィールドはプロトタイプではなく、各インスタンスに直接付与される。 |- | デフォルト値の設定 || フィールド宣言時に初期値を設定できる。<br>初期値を省略すると、<code>undefined</code> になる。 |} </center> <br> パブリックフィールド宣言の例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> class Temperature { // パブリックフィールド (デフォルト値を設定する) unit = "celsius"; value = 0; constructor(value, unit = "celsius") { this.value = value; this.unit = unit; } toCelsius() { if (this.unit === "fahrenheit") { return (this.value - 32) * 5 / 9; } return this.value; } toFahrenheit() { if (this.unit === "celsius") { return this.value * 9 / 5 + 32; } return this.value; } toString() { return this.value + "°" + this.unit.charAt(0).toUpperCase(); } } const temp = new Temperature(100, "celsius"); console.log(temp.toString()); // "100°C" console.log(temp.toFahrenheit()); // 212 </syntaxhighlight> <br> ==== プライベートフィールドとメソッド (#) ==== <code>#</code> 記法を使用することで、クラス外部からアクセスできないプライベートメンバーを定義できる。<br> <br> ES2022で正式仕様化され、カプセル化を強制する手段として広く使用される。<br> <br> プライベートメンバーの特性を以下に示す。<br> <br> <center> {| class="wikitable" |+ プライベートメンバーの特性 ! 特性 !! 説明 |- | クラス外からのアクセス禁止 || クラス外部から <code>#</code> フィールド や <code>#</code> メソッドにアクセスしようとすると<br><u>SyntaxError</u> が発生する。 |- | プライベートメソッドも同様 || メソッドにも <code>#</code> を付与することで、<br>クラス内部からのみ呼び出せるプライベートメソッドを定義できる。 |- | カプセル化の意義 || 内部実装の詳細を隠蔽することにより、<br>クラスの外部インターフェースを明確に保ち、保守性を高める。 |} </center> <br> プライベートフィールドとメソッドの使用例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> class BankAccount { // プライベートフィールド #balance; #owner; #transactionHistory = []; constructor(owner, initialBalance = 0) { this.#owner = owner; this.#balance = initialBalance; } // プライベートメソッド (内部処理のみで使用する) #recordTransaction(type, amount) { this.#transactionHistory.push({ type, amount, balance : this.#balance, timestamp : new Date().toISOString() }); } // パブリックメソッド (外部から呼び出すインターフェース) deposit(amount) { if (amount <= 0) { throw new Error("入金額は0より大きい値を指定してください"); } this.#balance += amount; this.#recordTransaction("deposit", amount); console.log(this.#owner + " さんの残高: " + this.#balance + " 円"); } withdraw(amount) { if (amount > this.#balance) { throw new Error("残高が不足しています"); } this.#balance -= amount; this.#recordTransaction("withdraw", amount); console.log(this.#owner + " さんの残高: " + this.#balance + " 円"); } get balance() { return this.#balance; } } const account = new BankAccount("太郎", 10000); account.deposit(5000); // "太郎 さんの残高: 15000 円" account.withdraw(3000); // "太郎 さんの残高: 12000 円" // console.log(account.#balance); // SyntaxError: クラス外からはアクセスできない </syntaxhighlight> <br><br> == 静的メソッドとプロパティ == <code>static</code> キーワードを使用することで、インスタンスではなくクラス自体に属するメソッドとプロパティを定義できる。<br> <br> 静的メンバーは、クラス名から直接アクセスする。<br> <br> ==== 静的メソッド ==== 静的メソッドは、インスタンスを生成せずにクラスから直接呼び出せるメソッドである。<br> <br> ファクトリパターン (特定の条件でインスタンスを生成するメソッド) や ユーティリティ関数としての用途に適している。<br> <br> 静的メソッドの使用例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> class User { constructor(name, email, role) { this.name = name; this.email = email; this.role = role; } // ファクトリメソッド : 管理者ユーザを生成する static createAdmin(name, email) { return new User(name, email, "admin"); } // ファクトリメソッド : 一般ユーザを生成する static createGuest(name) { return new User(name, "guest@example.com", "guest"); } // ユーティリティメソッド: メールアドレスの検証 static isValidEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); } toString() { return this.name + " (" + this.role + ")"; } } // インスタンスを生成せずに静的メソッドを呼び出す const admin = User.createAdmin("管理者", "admin@example.com"); const guest = User.createGuest("ゲスト"); console.log(admin.toString()); // "管理者 (admin)" console.log(guest.toString()); // "ゲスト (guest)" console.log(User.isValidEmail("test@example.com")); // true </syntaxhighlight> <br> ==== 静的プロパティ ==== 静的プロパティは、クラスレベルで共有される値を保持するために使用する。<br> <br> クラス全体に共通する定数やカウンタの管理に適している。<br> <br> 静的プロパティの使用例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> class DatabaseConnection { // 静的プロパティ: クラス全体で共有する設定値 static MAX_CONNECTIONS = 10; static #instanceCount = 0; // プライベートな静的プロパティ constructor(host, port) { if (DatabaseConnection.#instanceCount >= DatabaseConnection.MAX_CONNECTIONS) { throw new Error("接続数の上限 (" + DatabaseConnection.MAX_CONNECTIONS + ") に達しました"); } this.host = host; this.port = port; DatabaseConnection.#instanceCount++; console.log("接続を確立しました (現在の接続数: " + DatabaseConnection.#instanceCount + ")"); } // 静的メソッドから静的プロパティにアクセスする static getInstanceCount() { return DatabaseConnection.#instanceCount; } close() { DatabaseConnection.#instanceCount--; console.log("接続を閉じました (現在の接続数: " + DatabaseConnection.#instanceCount + ")"); } } const db1 = new DatabaseConnection("localhost", 5432); // "接続を確立しました (現在の接続数: 1)" const db2 = new DatabaseConnection("localhost", 5433); // "接続を確立しました (現在の接続数: 2)" console.log(DatabaseConnection.getInstanceCount()); // 2 console.log(DatabaseConnection.MAX_CONNECTIONS); // 10 db1.close(); // "接続を閉じました (現在の接続数: 1)" </syntaxhighlight> <br> 下表に、インスタンスメンバーと静的メンバーの比較を示す。<br> <br> <center> {| class="wikitable" |+ インスタンスメンバー vs 静的メンバー ! 項目 !! インスタンスメンバー !! 静的メンバー |- | 定義方法 || 通常の定義 || <code>static</code> キーワードを付与 |- | アクセス方法 || <code>instance.member</code> || <code>ClassName.member</code> |- | 共有範囲 || 各インスタンスが個別に保持 || クラス全体で1つを共有 |- | 用途 || インスタンス固有のデータ・処理 || ユーティリティ、定数、ファクトリ |- | <code>this</code> の参照先 || インスタンスを参照する || クラス自体を参照する |} </center> <br><br> == クラス式 == クラスは宣言 (class文) だけでなく、式 (クラス式) としても記述できる。<br> クラス式は変数に代入したり、関数の引数として渡したりすることができる。<br> <br> クラス式には無名クラス式と名前付きクラス式の2種類がある。<br> <u>名前付きクラス式の名前はクラスの内部 (メソッド内の再帰呼び出し等) からのみアクセスでき、クラス外部からは参照できない。</u><br> <br> クラス式の例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> // 無名クラス式 : 変数に代入する const Animal = class { constructor(name, sound) { this.name = name; this.sound = sound; } speak() { console.log(this.name + " は " + this.sound + " と鳴く"); } }; const dog = new Animal("犬", "ワン"); dog.speak(); // "犬 は ワン と鳴く" // 名前付きクラス式 : クラス名はクラス内部からのみ参照できる const Fibonacci = class FibClass { constructor(n) { this.n = n; } compute() { if (this.n <= 1) return this.n; // 内部からは、FibClassという名前でアクセスできる return new FibClass(this.n - 1).compute() + new FibClass(this.n - 2).compute(); } }; const fib = new Fibonacci(10); console.log(fib.compute()); // 55 // クラス外部からFibClassという名前にはアクセスできない // console.log(FibClass); // ReferenceError </syntaxhighlight> <br><br> == Reactとクラス構文 == React.Componentを継承することで、クラスコンポーネントを作成できる。<br> クラスコンポーネントでは、<code>constructor</code> で <code>this.state</code> を初期化し、<code>render</code> メソッドでJSXを返す。<br> <br> 現在は関数コンポーネントとHooksが主流であり、クラスコンポーネントを新規に作成する場面は少ない。<br> ただし、ErrorBoundaryのようにライフサイクルメソッド (<code>componentDidCatch</code> / <code>getDerivedStateFromError</code>) を必要とする機能は、クラスコンポーネントでのみ実装できる。<br> <br> <u>ErrorBoundaryの詳細については、[[JavaScriptの基礎 - 継承とプロトタイプ]]のページを参照すること。</u><br> <br> シンプルなReactクラスコンポーネントの例を以下に示す。<br> <br> <syntaxhighlight lang="javascript"> import React from "react"; class Counter extends React.Component { // パブリックフィールドでstateを宣言する (constructor不要) state = { count : 0 }; // クラスフィールドとアロー関数でthisを固定する handleIncrement = () => { this.setState(prevState => ({ count: prevState.count + 1 })); }; handleDecrement = () => { this.setState(prevState => ({ count: prevState.count - 1 })); }; handleReset = () => { this.setState({ count: 0 }); }; // renderメソッドでJSXを返す render() { return ( <div> <p>カウント: {this.state.count}</p> <button onClick={this.handleIncrement}>+1</button> <button onClick={this.handleDecrement}>-1</button> <button onClick={this.handleReset}>リセット</button> </div> ); } } export default Counter; </syntaxhighlight> <br><br> == 関連情報 == * [[JavaScriptの基礎 - 継承とプロトタイプ]] *: クラスの継承 (extends/super)、プロトタイプチェーン、ReactのErrorBoundary * [[JavaScriptの基礎 - thisキーワード]] *: thisの動作、bind/call/apply、クラスにおけるthis * [[JavaScriptの基礎 - オブジェクトリテラル]] *: オブジェクトの作成と操作、プロパティアクセス、メソッド * [[JavaScriptの基礎 - アロー関数]] *: アロー関数の構文、レキシカルthis <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:Web]]
JavaScriptの基礎 - クラス
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse