前書き

JavaScriptはプロトタイプベースの言語であり、JavaScriptのすべてのオブジェクトには、オブジェクトのプロパティとメソッドを拡張するために使用できる `+ +`と呼ばれる非表示の内部プロパティがあります。 プロトタイプの詳細については、https://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript [JavaScriptのプロトタイプと継承を理解する]チュートリアルをご覧ください。

最近まで、勤勉な開発者はhttps://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript#constructor-functions[constructor functions]を使用してJavaScriptのオブジェクト指向設計パターンを模倣していました。 ES6と呼ばれることが多い言語仕様ECMAScript 2015では、JavaScript言語にクラスが導入されました。 JavaScriptのクラスは、実際には追加の機能を提供しません。また、よりクリーンでエレガントな構文を提供するという点で、プロトタイプと継承よりも「構文糖」を提供すると言われます。 他のプログラミング言語はクラスを使用するため、JavaScriptのクラス構文により、開発者は言語間を簡単に移動できます。

クラスは関数です

JavaScriptクラスは関数の一種です。 クラスは `+ class`キーワードで宣言されます。 関数を初期化するには関数式構文を使用し、クラスを初期化するにはクラス式構文を使用します。

// Initializing a function with a function expression
const x = function() {}
// Initializing a class with a class expression
const y = class {}

`を使用して、オブジェクトの ` [[Prototype] `にアクセスできます。 Object.getPrototypeOf() `メソッド]。 それを使用して、作成した空の*関数*をテストします。

Object.getPrototypeOf(x);
Outputƒ () { [native code] }

作成した* class *でそのメソッドを使用することもできます。

Object.getPrototypeOf(y);
Outputƒ () { [native code] }

+ function`と + class`で宣言されたコードは両方とも関数 `+ `を返します。 プロトタイプでは、 ` new +`キーワードを使用して、任意の関数をコンストラクターインスタンスにできます。

const x = function() {}

// Initialize a constructor from a function
const constructorFromFunction = new x();

console.log(constructorFromFunction);
Outputx {}
constructor: ƒ ()

これはクラスにも当てはまります。

const y = class {}

// Initialize a constructor from a class
const constructorFromClass = new y();

console.log(constructorFromClass);
Outputy {}
constructor: class

これらのプロトタイプコンストラクターの例は、それ以外は空ですが、構文の下で、両方のメソッドが同じ最終結果を達成していることがわかります。

クラスを定義する

https://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript#constructor-functions [プロトタイプと継承チュートリアル]では、テキストでのキャラクター作成に基づいた例を作成しました-ベースのロールプレイングゲーム。 ここからその例を続けて、構文を関数からクラスに更新します。

*コンストラクター関数*は、関数自体を参照する `+ this +`のプロパティとして割り当てられるいくつかのパラメーターで初期化されます。 識別子の最初の文字は慣例により大文字になります。

constructor.js

// Initializing a constructor function
function Hero(name, level) {
   this.name = name;
   this.level = level;
}

これを以下に示す* class *構文に変換すると、非常によく似た構造になっていることがわかります。

class.js

// Initializing a class definition
class Hero {
   constructor(name, level) {
       this.name = name;
       this.level = level;
   }
}

コンストラクター関数は、イニシャライザーの最初の文字の大文字化(オプション)により、構文に精通していることにより、オブジェクトの設計図であることを知っています。 `+ class +`キーワードは、関数の目的をより簡単な方法で伝えます。

初期化の構文の唯一の違いは、 `+ function `の代わりに ` class `キーワードを使用し、 ` constructor()+`メソッド内でプロパティを割り当てることです。

メソッドの定義

コンストラクター関数の一般的な慣習は、以下の `+ greet()`メソッドに見られるように、初期化ではなく、 ` prototype +`にメソッドを直接割り当てることです。

constructor.js

function Hero(name, level) {
   this.name = name;
   this.level = level;
}

// Adding a method to the constructor
Hero.prototype.greet = function() {
   return `${this.name} says hello.`;
}

クラスを使用すると、この構文が簡素化され、メソッドをクラスに直接追加できます。 ES6で導入されたhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions[method definition shorthand]を使用して、メソッドを定義することはさらに簡潔なプロセスです。

class.js

class Hero {
   constructor(name, level) {
       this.name = name;
       this.level = level;
   }

   // Adding a method to the constructor
   greet() {
       return `${this.name} says hello.`;
   }
}

これらのプロパティとメソッドの動作を見てみましょう。 `+ new `キーワードを使用して ` Hero +`の新しいインスタンスを作成し、いくつかの値を割り当てます。

const hero1 = new Hero('Varg', 1);

新しいオブジェクトに関する詳細情報を `+ console.log(hero1)+`で出力すると、クラスの初期化で何が起こっているかについての詳細を見ることができます。

OutputHero {name: "Varg", level: 1}
__proto__:
 ▶ constructor: class Hero
 ▶ greet: ƒ greet()

出力では、 + constructor()+`と `+ greet()+`関数が `+ proto +、または `+ hero1 `の ` `に適用されたことがわかります。そして、 ` hero1 +`オブジェクトのメソッドとして直接ではありません。 コンストラクター関数を作成する場合、これは明らかですが、クラスの作成中には明らかではありません。 クラスを使用すると、よりシンプルで簡潔な構文を使用できますが、プロセスの明確さを犠牲にします。

クラスを拡張する

コンストラクター関数とクラスの有利な機能は、親に基づいて新しいオブジェクトブループリントに拡張できることです。 これにより、類似しているが追加の機能またはより具体的な機能が必要なオブジェクトのコードの繰り返しが防止されます。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call [+ call()+]メソッドを使用して、親から新しいコンストラクター関数を作成できます。 以下の例では、 `+ Mage `というより具体的な文字クラスを作成し、 ` call()`を使用して ` Hero +`のプロパティを割り当て、さらにプロパティを追加します。

constructor.js

// Creating a new constructor from the parent
function Mage(name, level, spell) {
   // Chain constructor with call
   Hero.call(this, name, level);

   this.spell = spell;
}

この時点で、「+ Hero 」と同じプロパティと追加した新しいプロパティを使用して、「 Mage +」の新しいインスタンスを作成できます。

const hero2 = new Mage('Lejon', 2, 'Magic Missile');

コンソールに「+ hero2 」を送信すると、コンストラクターに基づいて新しい「 Mage +」を作成したことがわかります。

OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}
__proto__:
   ▶ constructor: ƒ Mage(name, level, spell)

ES6クラスでは、「+ call 」の代わりにhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super [` super `]キーワードを使用して親にアクセスします機能。 親クラスを参照するには、 ` extends +`を使用します。

class.js

// Creating a new class from the parent
class Mage extends Hero {
   constructor(name, level, spell) {
       // Chain constructor with super
       super(name, level);

       // Add a new property
       this.spell = spell;
   }
}

これで、同じ方法で新しい「+ Mage +」インスタンスを作成できます。

const hero2 = new Mage('Lejon', 2, 'Magic Missile');

コンソールに `+ hero2 +`を出力し、出力を表示します。

OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}
__proto__: Hero
   ▶ constructor: class Mage

出力はほぼ同じですが、クラスの構築で + +`が親(この場合は `+ Hero +)にリンクされる点が異なります。

以下は、初期化、メソッドの追加、およびコンストラクター関数とクラスの継承のプロセス全体の並列比較です。

constructor.js

function Hero(name, level) {
   this.name = name;
   this.level = level;
}

// Adding a method to the constructor
Hero.prototype.greet = function() {
   return `${this.name} says hello.`;
}

// Creating a new constructor from the parent
function Mage(name, level, spell) {
   // Chain constructor with call
   Hero.call(this, name, level);

   this.spell = spell;
}

class.js

// Initializing a class
class Hero {
   constructor(name, level) {
       this.name = name;
       this.level = level;
   }

   // Adding a method to the constructor
   greet() {
       return `${this.name} says hello.`;
   }
}

// Creating a new class from the parent
class Mage extends Hero {
   constructor(name, level, spell) {
       // Chain constructor with super
       super(name, level);

       // Add a new property
       this.spell = spell;
   }
}

構文はまったく異なりますが、基本的な結果は両方の方法でほぼ同じです。 クラスはオブジェクトの青写真を作成するより簡潔な方法を提供し、コンストラクター関数は内部で何が起こっているかをより正確に記述します。

結論

このチュートリアルでは、JavaScriptコンストラクター関数とES6クラスの類似点と相違点について学びました。 クラスとコンストラクターの両方が、プロトタイプベースの継承言語であるJavaScriptに対するオブジェクト指向の継承モデルを模倣します。

プロトタイプの継承を理解することは、効果的なJavaScript開発者になるために最も重要です。 Reactなどの一般的なJavaScriptライブラリは `+ class +`構文を頻繁に使用するため、クラスに精通していると非常に役立ちます。