Javascript基礎知識編(4):対象への継承

16842 ワード

私たちが常に直面している対象向けの高級言語の中では、継承はすでにありふれた話題となっています.しかし、javascriptという非常に融通性のある言語にとっては、継承は複雑な技術である.継承はいったいどんなメリットをもたらすのでしょうか?もし私達がより多くの重複性の仕事を減らしたいならば、弱体化の対象間の結合性、既存の種類の基礎の上でそして十分にすでに備えた方法を利用して設計して、それでは継承して1種のもっと良い解決案になります.私たちが望む目標を達成するために、クラスで継承したり、プロトタイプで継承したりすることができます.ある人が聞きます.私は二つの種類がありますが、いわゆる「is a」という関係はありません.でも、同じ方法で呼びます.どうすればいいですか?私たちは対象に向けてインタフェースを使って実現できることを知っています.この文章では、このような問題を解決するために混元を採用し、場面に合うことを検討します.  
     まず、クラスの継承から話します.前の文章を読んだら、JSの中でどのように一つのクラスを作るかはすでに胸に成算があります.例から説明します.簡単なクラスのPersonを定義し、オブジェクトを実装します.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
var reader = new Person("Miracle");
reader.getName();//Miracle
次にPersonのサブクラスAuthorを追加します.父の種類を継承する方法はどうですか?
function Author(name, books) {
Person.call(this, name);
this.books = books;
}
Author.prototype = new Person();
Author.prototype.constructor = Author;
Author.prototype.getBooks = function() {
return this.books;
}
var author = new Author("Miracle He", ["JavaScript Learning"]);
author.getName();
author.getBooks();
上のコードがよく分からない友達がいるかもしれませんが、その中のいくつかの文に対して重点的に説明します.まずAuthorのコンストラクタを作成しました.new演算子を使ってオブジェクトを作成する場合、まず空のオブジェクトを作成してコンストラクタを呼び出すとともに、この空のオブジェクトはスコープの最前端に位置します.ここでPersonは自己のコンストラクタを呼び出して、nameパラメータを入力して、賦課を実現します.次はAuthor.prototype=new Personです.JSではどのオブジェクトにもプロトタイプという属性があることが知られていますが、そのオブジェクトを呼び出す方法においては、まずその対象のクラスから探します.存在しない場合は、このタイプのプロトタイプのカテゴリーまで探し続けます.PersonをAuthorの原型として与えた以上、次にconstructor属性をAuthorにリセットします.上記のコードから、継承は難しいものの、サブクラスの呼び出しは非常に簡単であることが分かります.次にコードを再構築します.拡張方法を追加しました.
function extend(subclass, superclass) {
var F = function() {};
F.prototype = superclass.prototype;
subclass.prototype = new F();
subclass.prototype.constructor = subclass;
}
function Author(name, books) {
Person.call(this, name);
this.books = books;
}
extend(Author, Person);
Author.prototype.getBooks = function() {
return this.books;
}
AuthorのコンストラクターにはPersonという固化された姿があるということも分かりました.私たちはすぐにそれを一般化しました.
function extend(subclass, superclass) {
var F = function() {};
F.prototype = superclass.prototype;
subclass.prototype = new F();
subclass.prototype.constructor = subclass;

subclass.parent = superclass.prototype;
if(superclass.prototype.constructor == Object.prototype.constructor) {
superclass.prototype.constructor = superclass;
}
}
function Author(name, books) {
Author.parent.constructor.call(this, name);
this.books = books;
}
extend(Author, Person);
Author.prototype.getBooks = function() {
return this.books;
}
     次に、原型式の継承を紹介します.クラス継承とは全く違って、クラスでオブジェクトの構造を定義する必要はなく、オブジェクトを直接作成すればいいです.プロトタイプチェーン検索の機構を利用して,新しいオブジェクトの再利用,すなわち他のオブジェクトのためのモデルを提供し,それをプロトタイプオブジェクトと仮称した.以下はプロトタイプの継承を利用してPersonとAuthorを書き直します.
var Person= {
name: "default name",
getName: function() {
return this.name;
}
};
function clone(object) {
function F() {}
F.prototype = object;
return new F;
}
var reader = clone(Person);
alert(reader.getName());//"default name"
reader.name = "Miracle";
alert(reader.getName());//"Miracle"
おそらくみんなが最も関心を持っているのは「clone」の関数ではないでしょうか?簡単な言葉で一つのオブジェクトのコピーを完成しました.一番重要なのはプロトタイプの役割です.ちなみに、プロトタイプ属性は原型の対象を指すために使用され、プロトタイプリンク機構を通じてすべての継承にメンバーのリンクを提供します.継承対象となるAuthorを作るのは簡単です.
var Author = clone(Person);
Author.books = [];
Author.getBooks = function() {
return this.books;
};
var author = clone(Author);
author.name = "Miracle He";
author.books = ["Javascript Learning"];
alert(author.getName());//"Miracle He"
alert(auhtor.getBooks());//"Javascript Learning"
     元のオブジェクトの方法と属性を再定義することができ、新しい方法と属性を定義することもできます.クラス継承では、Authorが生成した各例には、book s属性のコピーがあるが、プロトタイプ継承によって生成されたインスタンスbook sは、常に完全に独立したコピーではなく、プロトタイプオブジェクトの空のオブジェクトを指すだけである.みんなはこの話に対して難しいと感じるかもしれませんが、例を挙げて説明します.
var miracle = clone(Author);
var mike = clone(Author);
miracle.books.push("Javascript Learning");
alert(mike.books);//??
このコードを見たら、結果が出ましたか?教えたいのですが、mike.book sにも「Javascript Learning」という本が含まれていますが、なぜですか?miracle.book sはpushを実行する前にAuthor.book sを指す空の対象であるため、pushを実行すると元のオブジェクトが自然にmiracleによってpushされた本を持っています.mikeはAuthorの継承対象です.もちろん持っています.これは私たちが達成したい効果ではないかもしれません.いつも言っているように、引用されたデータの種類を伝えて新しいコピーを作成しなければなりません.どうやって上記の問題を解決しますか?私たちは対象のpushを引き継ぐ前にbook sをクリアして追加することができます.サブオブジェクトがある原型オブジェクトは、どのようにオブジェクト間の結合が弱体化されているかを見てみましょう.
var GameTeams = {
name: "Dreams",
member: {
color: "blue",
count: 5
}
};
var miracle = clone(GameTeams);
miracle.member.count = 6;// ( GameTeams.member.count)
miracle.member = {
color: "blue",
count: 6
};
//
var GameTeams = {};
GameTeams.name = "Dream";
GameTeams.createMember = function() {
return {
color: "blue",
count: 5
};
};
GameTeams.member = GameTeams.createMember();
var miracle = clone(GameTeams);
miracle.member = GameTeams.createMember();
miracle.member.count = 6;
      類式の継承と原型式の継承について話しましたが、どのように混元類が何ですか?単純な理解は、関数を複数のクラスに使用し、これらのクラスを拡張する方法で共有することです.具体的な方法は、まず共通の方法を含むクラスを作成し、それ自体がインスタンス化されたり、直接呼び出しられたりするのではなく、他の種類のために自分の方法を提供します.実際のコードで説明します.
var Mixin = function() {};
Mixin.prototype = {
serialize: function() {
var output = [];
for(key in this) {
output.push(key + ":" + this[key]);
}
return output.join(",");
}
};
以上では、現在のオブジェクトのすべてのメンバーを巡回し、文字列で出力するための一般的な方法serializeを含むミキシングクラスを定義しました.これを使ってAuthorクラスを拡張できます.
function augment(receivingClass, givingClass) {
//
if(arguments[2]) {
for(var i = 2, len = arguments.length; i < len; i++) {
var method = arguments[i];
if(!receivingClass.prototype[method]) {
receivingClass.prototype[method] = givingClass.prototype[method];
}
}
} else {
for(method in givingClass.prototype) {
if(!receivingClass.prototype[method]) {
receivingClass.prototype[method] = givingClass.prototype[method];
}
}
}
}
augment(Author, Mixin);
augment(Author, Mixin, "serialize");
var author = new Author("Miracle", ["Javascript Learning"]);
var result = author.serialize();
いくつかの共通の方法で複数のクラスを拡張することは、このクラスの継承よりも適切であり、特にお互いの違いが大きいクラスであるが、共通の方法を共有する必要がある場合がある.クラスの継承、プロトタイプの継承と混成の種類を理解することによって、私達は総合的に3つの共通点の実現方式を書き出して、直接にソースコードを提供して、注釈はその中に含まれます.
/*         extend  ,    */  
Function.prototype.extend = function(superClass) {
if(superClass === 'function') {
//
var F = function() {};//
F.prototype = superClass.prototype;//
this.prototype = new F();// F,
this.prototype.constructor = this;//
this.superClass = superClass;// , ,
} else if(superClass === 'object') {
//
var pro = this.prototype;
for(var k in superClass) {
if(!pro[k]) {
//
pro[k] = superClass[k];
}
}
} else {
throw new Error('fatal error: "Function.prototype.extend" expects a function or a object');
}
return this;
};
使い方は以下の通りです
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
};

function Author(name, books) {
Author.superClass.call(this, name);
this.books = books;
}
//
Author.extend(Person).prototype.getBooks = function() {
return this.books;
};
// , superClass ,
Author.prototype.getName = function() {
var name = Author.superClass.prototype.getName.call(this);
return name + ", Author of " + this.getBooks();
}
//
Author.extend({
serialize: function() {
var output = [];
for(key in this) {
output.push(key + ":" + this[key]);
}
return output.join(",");
}
});
以上で、継承についての話は終わりましたが、もっと深いものがあります.