[解決済み】javascriptの古典的な継承とプロトタイプの継承の比較
質問
古典的な継承とプロトタイプ継承の違いについて、いろいろ調べてみたのですが、よくわかりません。
このページでいくつかのことを学びましたが、まだコンセプトについて混乱しています。
古典的な継承
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
//superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
//subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
古典的な継承は、内部でプロトタイプ継承を使うのですか?
http://aaditmshah.github.io/why-prototypal-inheritance-matters/
上記のリンクから、私は次のことを知りました。 古典的な継承では、実行時に新しいメソッドを追加することはできません。 . これは正しいのでしょうか?しかし、あなたは上記のコードを確認することができます プロトタイプを使用して、実行時に "move" メソッドと任意のメソッドを追加することができます。 . これはプロトタイプベースの古典的継承なのですか?もしそうなら、古典継承とプロトタイプ継承とは何なのでしょうか?私はそれについて混乱しています。
プロトタイプの継承。
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function () {
var radius = this.radius;
return Math.PI * radius * radius;
};
Circle.prototype.circumference: function () {
return 2 * Math.PI * this.radius;
};
var circle = new Circle(5);
var circle2 = new Circle(10);
これは古典的な継承と似ているのでしょうか?プロトタイプ継承とは何なのか、全く分からないのですが?古典的な継承とは何ですか?古典的な継承はなぜ悪いのですか?
これらをわかりやすく理解するために、簡単な例を教えてください。
ありがとうございます。
シバ
解決方法は?
ご質問のコードサンプルは、いずれもプロトタイプ継承を利用しています。実際、あなたがJavaScriptで書くオブジェクト指向のコードはすべてプロトタイプ継承のパラダイムです。JavaScriptには古典的な継承がないのです。これで少しはすっきりしたのではないでしょうか。
Inheritance
|
+-----------------------------+
| |
v v
Prototypal Classical
|
+------------------------------+
| |
v v
Prototypal Pattern Constructor Pattern
プロトタイプ継承と古典的継承は異なる継承のパラダイムであることがおわかりいただけたと思います。SelfやLua、JavaScriptのようにプロトタイピング継承をサポートする言語もあります。しかし、C++、Java、C#のようなほとんどの言語では、古典的な継承をサポートしています。
オブジェクト指向プログラミングの簡単な概要
プロトタイプ継承と古典的継承は、どちらもオブジェクト指向のプログラミングパラダイムです(つまり、オブジェクトを扱います)。オブジェクトは、現実世界の実体の特性をカプセル化した抽象的なものです(つまり、プログラムの中で現実の言葉を表すものです)。これを「抽象化」という。
抽象化すること。 現実世界のものをコンピュータのプログラムで表現すること。
理論的には、抽象化とは「特定の例から共通の特徴を抽出することによって形成される一般的な概念」と定義される。しかし、この説明では、代わりに前述の定義を使用することにする。
さて、物には多くの共通点を持つものがあります。例えば、泥んこ自転車とハーレーダビッドソンには多くの共通点があります。
泥んこバイク。
ハーレーダビッドソンです。
泥んこバイクもハーレーダビッドソンもバイクである。したがって、バイクは泥んこバイクとハーレーダビッドソンの両方を一般化したものである。
Bike
|
+---------------------------------+
| |
v v
Mud Bike Harley Davidson
上の例では、バイク、泥んこバイク、ハーレーダビッドソンはすべて抽象的なものです。しかし、バイクは泥バイクとハーレーダビッドソンをより一般的に抽象化したものです(つまり、泥バイクもハーレーダビッドソンも特定のタイプのバイクです)。
一般化すること。 より具体的なものを抽象化したもの。
オブジェクト指向プログラミングでは、オブジェクト(現実世界の実体を抽象化したもの)を作成し、クラスやプロトタイプを使って、これらのオブジェクトの汎化されたものを作成します。汎化は継承によって行われます。バイクは泥付きバイクの汎化です。したがって、泥んこ自転車は自転車から継承される。
古典的なオブジェクト指向プログラミング
古典的なオブジェクト指向プログラミングでは、クラスとオブジェクトという2種類の抽象化されたものがあります。オブジェクトは、先に述べたように、現実世界の実体を抽象化したものである。一方、クラスは、オブジェクトや他のクラスを抽象化したものである(つまり、汎化されたものである)。例えば、考えてみよう。
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | Man | Class of object johnDoe. |
| 3 | Human | Superclass of class Man. |
+----------------------+----------------+---------------------------------------+
古典的なオブジェクト指向プログラミング言語では、オブジェクトは抽象化に過ぎず(つまり、すべてのオブジェクトは抽象度1)、クラスは一般化に過ぎない(つまり、すべてのクラスは1より大きい抽象度を持つ)ことがおわかりいただけると思います。
古典的なオブジェクト指向プログラミング言語では、オブジェクトはクラスのインスタンス化によってのみ生成される。
class Human {
// ...
}
class Man extends Human {
// ...
}
Man johnDoe = new Man();
要約すると、古典的なオブジェクト指向プログラミング言語では、オブジェクトは現実世界の実体の抽象化であり、クラスは一般化(すなわち、オブジェクトまたは他のクラスの抽象化)です。
したがって、抽象度が上がると実体はより一般的になり、抽象度が下がると実体はより具体的になる。この意味で、抽象度は、より具体的な実体からより一般的な実体へと至る尺度に類似している。
プロトタイプ・オブジェクト指向プログラミング
プロトタイプオブジェクト指向プログラミング言語は、古典的なオブジェクト指向プログラミング言語よりもはるかにシンプルです。なぜなら、プロトタイプオブジェクト指向プログラミングでは、1種類の抽象化(つまり、オブジェクト)しか存在しないからです。例えば、考えてみましょう。
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | man | Prototype of object johnDoe. |
| 3 | human | Prototype of object man. |
+----------------------+----------------+---------------------------------------+
プロトタイプ型オブジェクト指向プログラミング言語では、オブジェクトは現実世界の実体(この場合、単にオブジェクトと呼ばれる)または他のオブジェクト(この場合、抽象化したオブジェクトのプロトタイプと呼ばれる)の抽象化であることがおわかりいただけると思います。つまり、プロトタイプは汎化である。
プロトタイプオブジェクト指向プログラミング言語におけるオブジェクトは、無から創り出すことも、別のオブジェクトから創り出すこともできる(新たに創り出すオブジェクトのプロトタイプになる)。
var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);
プロトタイプオブジェクト指向プログラミング言語が古典的なオブジェクト指向プログラミング言語よりも強力である理由は、私の謙虚な意見にあります。
- 抽象化は1種類しかない。
- 一般化とは、単なるオブジェクトのことです。
ここまでで、古典的な継承とプロトタイプ継承の違いに気づかれたことでしょう。古典的な継承は、クラスが他のクラスを継承することに限定されます。しかし、プロトタイプ継承は、プロトタイプが他のプロトタイプを継承するだけでなく、プロトタイプからオブジェクトを継承することも含まれます。
プロトタイプ-クラス同型性
プロトタイプとクラスが非常によく似ていることにお気づきでしょうか。その通りです。そうなんです。実際、クラスをモデリングするのにプロトタイプを使うことができるほど似ています。
function CLASS(base, body) {
if (arguments.length < 2) body = base, base = Object.prototype;
var prototype = Object.create(base, {new: {value: create}});
return body.call(prototype, base), prototype;
function create() {
var self = Object.create(prototype);
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
}
}
上記を利用して
CLASS
を使用すると、クラスのようなプロトタイプを作成することができます。
var Human = CLASS(function () {
var milliseconds = 1
, seconds = 1000 * milliseconds
, minutes = 60 * seconds
, hours = 60 * minutes
, days = 24 * hours
, years = 365.2425 * days;
this.constructor = function (name, sex, dob) {
this.name = name;
this.sex = sex;
this.dob = dob;
};
this.age = function () {
return Math.floor((new Date - this.dob) / years);
};
});
var Man = CLASS(Human, function (Human) {
this.constructor = function (name, dob) {
Human.constructor.call(this, name, "male", dob);
if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
};
});
var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));
しかし、逆は真ではない(つまり、プロトタイプをモデル化するためにクラスを使用することはできない)。これは、プロトタイプはオブジェクトですが、クラスはオブジェクトではないからです。これは、プロトタイプはオブジェクトですが、クラスはオブジェクトではないからです。クラスはまったく異なるタイプの抽象化です。
結論
要約すると、抽象化とは、以下のようなものであることを学びました。 具体的な事例から共通の特徴を抽出することによって形成される一般的な概念。 そして、一般化とは より具体的な抽象化の抽象化。 . また、プロトタイプ継承と古典的継承の違いや、両者が同じコインの裏表であることについても学びました。
最後に、プロトタイプ継承には、プロトタイプ・パターンとコンストラクタ・パターンの2つがあることを述べておきたい。プロトタイパルパターンはプロトタイパル継承の標準的なパターンであり、コンストラクタパターンはプロトタイパル継承をより古典的な継承に近づけるために使われるパターンである。個人的には、プロトタイパルパターンの方が好きです。
関連
-
[解決済み】Heroku:ノードアプリで「このアプリにはデフォルトの言語が検出されませんでした」エラーがスローされる
-
[解決済み】JavaScriptで相対URLへのリダイレクトを行う
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでオブジェクトをディープクローンする最も効率的な方法は何ですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 Uncaught TypeError: data.push is not a function
-
[解決済み】JavaScriptのisset()に相当するもの
-
[解決済み】BootstrapのCollapseが折りたたまれない
-
[解決済み】コンソールがUnterminated JSX contentsエラーを投げる【終了しました
-
[解決済み】PhantomJS 2.1.1を使用してReactJSアプリケーションをレンダリングできない理由とは?
-
[解決済み】ETIMEDOUTエラーの対処方法は?
-
[解決済み】HTMLの最初の行に予期しないトークン<がある。
-
[解決済み】module.exports "モジュールが定義されていません"
-
[解決済み】Javascript、[オブジェクトHTMLInputElement]を表示中。]
-
[解決済み】プロトタイプ継承の利点は古典的なものよりも?