[解決済み] ES2015 (ES6) の `class` 構文にはどのような利点があるのでしょうか?
質問
ES6クラスについて、いろいろと質問させてください。
を使用する利点は何ですか?
class
構文を使用する利点は何ですか?public/private/staticがES7に含まれると読みましたが、それが理由でしょうか?
さらに
class
は別の種類の OOP なのでしょうか、それとも JavaScript のプロトタイプ的な継承なのでしょうか?を使って修正することはできるのでしょうか?
.prototype
? それとも、同じオブジェクトでありながら、2つの異なる方法で宣言しているのでしょうか?
スピード面でのメリットはあるのでしょうか?ビッグアプリのような大きなアプリケーションであれば、メンテナンス/理解がしやすいのかも?
どのように解決するのか?
新しい
class
の構文は、完全ではないものの、ほとんどが構文上の糖分です (しかし、その
good
のようなものです)。コンストラクタ関数と、コンストラクタ関数が生成するオブジェクトのプロトタイプとして割り当てるオブジェクトの記述を著しく簡素化します。特に、ES5 構文ではエラーが発生しがちだった継承階層の設定を簡素化します。しかし、古い方法とは異なり
class
構文でも
super.example()
をスーパーコールに使用できるようになりました。
プロパティ宣言
,
プライベートフィールド
そして
プライベートメソッド
(を含む)。
静的メソッド
).
(たまに
class
構文を使わなければならないと言う人もいます。
Error
または
Array
[というように、ES5では適切にサブクラス化することができませんでした]。そんなことはありません、ES2015の別の機能を使えばいいのです。
Reflect.construct
[
スペック
,
MDN
を使いたくない場合は
class
の構文を使用します¹)。
さらに、は
class
は別の種類の OOP なのでしょうか、それとも JavaScript のプロトタイプの継承なのでしょうか?
今までと同じプロトタイプの継承で、よりクリーンで便利、そしてエラーが起こりにくい構文になっています。
もし
を使うのが好きなら、コンストラクタ関数 (
new Foo
など)を使うのが好きで、さらにいくつかの機能が追加されています。
を使って修正することは可能ですか?
.prototype
?
はい、あなたはまだ
prototype
オブジェクトを修正することができます。例:これは完全に合法です。
class Foo {
constructor(name) {
this.name = name;
}
test1() {
console.log("test1: name = " + this.name);
}
}
Foo.prototype.test2 = function() {
console.log("test2: name = " + this.name);
};
速度面でのメリットはありますか?
具体的なイディオムを用意することで、推測ですが
可能
を提供することで、エンジンはより良い最適化を行うことができるかもしれません。しかし、エンジンはすでに最適化するのが非常にうまいので、大きな違いはないと思います。特に
class
構文について特に言えることは、もしあなたが
プロパティ宣言
の数を最小限にすることができます。
形状の変更
を最小化することができ、コードの解釈と後のコンパイルを少し速くすることができます。しかし、繰り返しになりますが、それは大きなものではありません。
ES2015 (ES6) はどのような利点があるのでしょうか?
class
の構文がもたらす利点は何でしょうか?
簡単に説明します。そもそもコンストラクタ関数を使用しないのであれば
Object.create
などとする。
class
は、あなたにとって有用ではありません。
もしコンストラクタ関数を使うのであれば、いくつかの利点があります。
class
:
-
構文がよりシンプルになり、エラーが起こりにくくなりました。
-
それは 大いに 新しい構文で継承階層を設定する方が、古い構文よりずっと簡単です (そしてまた、エラーが起こりにくいです)。
-
class
を使用しないというよくある間違いからあなたを守ります。new
をコンストラクタ関数と一緒に使用することに失敗する一般的なエラーを防御します(コンストラクタが例外を投げるようにすることで)。 -
親プロトタイプのバージョンのメソッドを呼び出すことは、古い構文よりも新しい構文ではるかに簡単です (
super.method()
の代わりにParentConstructor.prototype.method.call(this)
またはObject.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)
). -
プロパティ宣言は、作成されるインスタンスの形状をコンストラクタのロジックから分離して明確にすることができます。
-
プライベートフィールドとメソッド(インスタンスと静的の両方)を
class
構文で使用でき、ES5 構文では使用できません。
以下は、階層の構文比較(プライベートメンバーなし)です。
// ***ES2015+**
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod() {
// ...
}
}
class Employee extends Person {
constructor(first, last, position) {
super(first, last);
this.position = position;
}
employeeMethod() {
// ...
}
}
class Manager extends Employee {
constructor(first, last, position, department) {
super(first, last, position);
this.department = department;
}
personMethod() {
const result = super.personMethod();
// ...use `result` for something...
return result;
}
managerMethod() {
// ...
}
}
例
// ***ES2015+**
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod() {
return `Result from personMethod: this.first = ${this.first}, this.last = ${this.last}`;
}
}
class Employee extends Person {
constructor(first, last, position) {
super(first, last);
this.position = position;
}
personMethod() {
const result = super.personMethod();
return result + `, this.position = ${this.position}`;
}
employeeMethod() {
// ...
}
}
class Manager extends Employee {
constructor(first, last, position, department) {
super(first, last, position);
this.department = department;
}
personMethod() {
const result = super.personMethod();
return result + `, this.department = ${this.department}`;
}
managerMethod() {
// ...
}
}
const m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());
vs.
// **ES5**
var Person = function(first, last) {
if (!(this instanceof Person)) {
throw new Error("Person is a constructor function, use new with it");
}
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
// ...
};
var Employee = function(first, last, position) {
if (!(this instanceof Employee)) {
throw new Error("Employee is a constructor function, use new with it");
}
Person.call(this, first, last);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.employeeMethod = function() {
// ...
};
var Manager = function(first, last, position, department) {
if (!(this instanceof Manager)) {
throw new Error("Manager is a constructor function, use new with it");
}
Employee.call(this, first, last, position);
this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
var result = Employee.prototype.personMethod.call(this);
// ...use `result` for something...
return result;
};
Manager.prototype.managerMethod = function() {
// ...
};
ライブの例です。
// **ES5**
var Person = function(first, last) {
if (!(this instanceof Person)) {
throw new Error("Person is a constructor function, use new with it");
}
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
return "Result from personMethod: this.first = " + this.first + ", this.last = " + this.last;
};
var Employee = function(first, last, position) {
if (!(this instanceof Employee)) {
throw new Error("Employee is a constructor function, use new with it");
}
Person.call(this, first, last);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.personMethod = function() {
var result = Person.prototype.personMethod.call(this);
return result + ", this.position = " + this.position;
};
Employee.prototype.employeeMethod = function() {
// ...
};
var Manager = function(first, last, position, department) {
if (!(this instanceof Manager)) {
throw new Error("Manager is a constructor function, use new with it");
}
Employee.call(this, first, last, position);
this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
var result = Employee.prototype.personMethod.call(this);
return result + ", this.department = " + this.department;
};
Manager.prototype.managerMethod = function() {
// ...
};
var m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());
見ての通り、そこには繰り返しの多い冗長なものがあり、間違えやすく、再入力するのも退屈です(私は昔、このためにスクリプトを使っていました、以前は
class
が登場する前は、このためにスクリプトを使っていました)。
注意しなければならないのは、ES2015のコードでは
Person
関数のプロトタイプが
Employee
関数のプロトタイプですが、ES5のコードではそうではありません。ES5では、そのような方法はありません。すべての関数で
Function.prototype
をプロトタイプとして使用します。環境によっては、サポートされている
__proto__
擬似プロパティをサポートしていて、それを変更することができたかもしれません。そのような環境では、このようにすることができます。
Employee.__proto__ = Person; // Was non-standard in ES5
もし、何らかの理由でこれを
function
構文の代わりに
class
を使用すると、ES2015+環境では、標準の
Object.setPrototypeOf
を使用します。
Object.setPrototypeOf(Employee, Person); // Standard ES2015+
しかし、ES2015+環境で古い構文を使用する強い動機が見当たりません(配管がどのように機能するかを理解するための実験以外には)。
(ES2015 はまた
__proto__
アクセサー・プロパティ
のラッパーです。
Object.setPrototypeOf
と
Object.getPrototypeOf
を追加することで、これらの非標準的な環境でのコードが標準になるようにしましたが、これはレガシーコードに対してのみ定義され、環境がこれを提供することを要求されないという意味で "規範的オプション" です)。
¹ 以下では
Reflect.construct
をサブクラスとして
Error
を使いたくなかった場合、(例えば)
class
の構文を使うことができます。
// Creating an Error subclass:
function MyError(...args) {
return Reflect.construct(Error, args, this.constructor);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
MyError.prototype.myMethod = function() {
console.log(this.message);
};
// Example use:
function outer() {
function inner() {
const e = new MyError("foo");
console.log("Callng e.myMethod():");
e.myMethod();
console.log(`e instanceof MyError? ${e instanceof MyError}`);
console.log(`e instanceof Error? ${e instanceof Error}`);
throw e;
}
inner();
}
outer();
.as-console-wrapper {
max-height: 100% !important;
}
関連
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] javascript:void(0)」とは何ですか?
-
[解決済み] jQuery.fnとは何ですか?
-
[解決済み] シンボルをES6に導入する動機は何ですか?
-
[解決済み】関数の前のエクスクラメーションマークは何をするのですか?
-
[解決済み】ES6クラス変数の代替品
-
[解決済み】ES6 WeakMapの実際の使い道は?
-
[解決済み】ES6のarrow関数構文をジェネレータで使用することはできますか?(アロー記法)
-
[解決済み】ES6クラスベースのReactコンポーネントと機能的なES6 Reactコンポーネントの使い分けはいつ?
-
[解決済み] 文字列がhtmlであるかどうかをチェックする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】関数内で "this "キーワードはどのように機能するのでしょうか?
-
[解決済み] JavaScript で範囲を作成する - 奇妙な構文
-
[解決済み] Javascriptによるタッチスクリーンデバイスの検出
-
[解決済み] React js 親コンポーネントから子コンポーネントの状態を変更する
-
[解決済み] AJAX Mailchimp サインアップフォームの統合
-
[解決済み] CORS: 認証モードは 'include' です。
-
[解決済み] Chromeのwebkitインスペクタで「Unsafe JavaScript attempt to access frame with URL...」というエラーが継続的に発生する。
-
[解決済み] JavaScript で css プロパティを使用して HTML 要素の背景色を設定する方法
-
[解決済み] 変異を伴わないオブジェクトからの値の削除
-
[解決済み] JavaScriptデータフォーマット/プリティプリンタ