JavaScript対象向けプログラミング——「対象継承」の注意点
10731 ワード
引き継ぐ
継承はインターフェースの継承と継承の実現に分けられます.インターフェースは継承方法の署名だけを継承して、継承を実現するには実際の方法を継承します.関数に署名がないため、ECMAScriptにはインターフェース継承がなく、プロトタイプチェーンによる継承のみが可能です.
原型チェーン
基本的な考え方は、プロトタイプチェーンを利用して、他の引用タイプの属性と方法を引継ぎます.
例えば:Person 2.prototypeはPerson 1.prototypeの継承であり、(「-」)は「指す」という意味である:
具体的にどのように継承しますか?
もう一つ例を挙げます
プロトタイプにメソッドを追加するコードは、プロトタイプを置き換える文の後に必ず入れてください.
プロトタイプチェーンを通して継承を実現した場合、字面を使ってプロトタイプを作成することはできません.
プロトタイプチェーンの問題は、すべてのインスタンスによって共有される参照タイプ値のプロトタイプを含む. は、サブタイプのインスタンスを作成する際に、スーパータイプのコンストラクターにパラメータを伝達することができない. 第一の問題について:
コンストラクタを借りる(推奨しない)
「構造関数の借用」と呼ばれる技術や偽造の対象や古典的な継承.例えば:
また、
コンビネーション継承(最も一般的なモード)
疑似経典継承とも呼ばれる.例えば:
重要です
重要です
重要です
以上
プロトタイプ継承
通常は一つの対象を他の対象と同じように維持したい場合、原型式継承は完全に可能です.対応する参照タイプの値の属性を共有します.
文法は:
寄生式継承(関数多重ができず効率が低下する)
パッケージの継承プロセスの関数を作成します.
基本的なロジックはまず超タイプのプロトタイプのコピーを作成します.コピーにconstructor属性を追加します.最後に副本をサブタイプの原型に割り当てます.例えば:
継承はインターフェースの継承と継承の実現に分けられます.インターフェースは継承方法の署名だけを継承して、継承を実現するには実際の方法を継承します.関数に署名がないため、ECMAScriptにはインターフェース継承がなく、プロトタイプチェーンによる継承のみが可能です.
原型チェーン
基本的な考え方は、プロトタイプチェーンを利用して、他の引用タイプの属性と方法を引継ぎます.
例えば:Person 2.prototypeはPerson 1.prototypeの継承であり、(「-」)は「指す」という意味である:
Person2.prototype - [[Prototype]] ---> Person1.prototype
Person2 - prototype ---> Person2
person2 - [[Prototype]] ---> Person2.prototype
//Person2.prototype constructor
Person1.prototype - cunstructor ---> Person1
Person1 - prototype ---> Person1.prototype
person1 - [[Prototype]] ---> Person1.prototype
具体的な方法具体的にどのように継承しますか?
function People(){}; //
People.prototype.sayWorld = function(){
return "World people"
};
function Person(){}; //
Person.prototype = new People(); //
Person.prototype.sayNation = function(){ // prototype
return "Chinese people"
};
var person = new Person(); //
console.log(person.sayNation()); //Chinese people
console.log(person.sayWorld()); //World people
気をつけてください!!プロトタイプにメソッドのコードを追加するには、プロトタイプを置き換えるステートメントの後に置く必要があります!!!もう一つ例を挙げます
function WorldPeople(){};
WorldPeople.prototype = {
constructor: WorldPeople,
color: "",
say: function(){
return "People in the Earth."
},
friends: ["Oliver","Alice","Troy"]
};
function Chinese(){};
Chinese.prototype = new WorldPeople();
Chinese.prototype.color = "yellow";
Chinese.prototype.say = function(){
return "i am Chinese."
};
var person1 = new Chinese();
console.log(person1.friends.toString());
console.log(person1.color);
console.log(person1.say());
/*
[Log] Oliver,Alice,Troy (repetition.html, line 163)
[Log] yellow (repetition.html, line 164)
[Log] i am Chinese. (repetition.html, line 165)
*/
原型と実例の関係を確定するinstanceof
オペレータとinsPrototypeOf()
方法を使えばいいです.console.log(person1 instanceof Object); //true;
console.log(person1 instanceof WorldPeople); //true;
console.log(person1 instanceof Chinese); //true;
console.log(Object.prototype.isPrototypeOf(person1)); //true
console.log(WorldPeople.prototype.isPrototypeOf(person1)); //true
console.log(Chinese.prototype.isPrototypeOf(person1)); //true
慎重に定義する方法プロトタイプにメソッドを追加するコードは、プロトタイプを置き換える文の後に必ず入れてください.
プロトタイプチェーンを通して継承を実現した場合、字面を使ってプロトタイプを作成することはできません.
プロトタイプチェーンの問題
function People(){}
People.prototype.friends = ["Alice","Oliver"];
function Person(){};
Person.prototype = new People();
var person1 = new Person();
var person2 = new People();
person1.friends.push("Troy");
console.log(person1.friends);
console.log(person2.friends); //
何か解決策がありますか?コンストラクタを借りる(推奨しない)
「構造関数の借用」と呼ばれる技術や偽造の対象や古典的な継承.例えば:
function People(){
this.friends = ["Alice","Oliver"];
}
function Person(){
People.call(this); // People
}
// Person.prototype = new People()
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Troy");
console.log(person1.friends); //["Alice", "Oliver", "Troy"]
console.log(person2.friends); //["Alice", "Oliver"]
この方法の主な利点は,サブタイプのコンストラクタにおいて,超タイプのコンストラクタにパラメータを伝えることができることである.また、
function SuperType(name){
this.name = name;
}
function SubType(){
SuperType.call(this,"Oliver"); // SuperType,
this.age = 18;
}
var person = new SubType();
console.log(person.name); //Oliver
console.log(person.age); //18
関数は多重化できないなどの問題のため、使用を推奨しません.コンビネーション継承(最も一般的なモード)
疑似経典継承とも呼ばれる.例えば:
//
function SuperType(name){
this.name = name;
this.colors = ["Blue","Red","Black"];
}
//
SuperType.prototype.sayName = function(){
return (this.name);
};
//
function SubType(name,age){
SuperType.call(this,name);//
this.age = age;//
}
//
SubType.prototype = new SuperType();//
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){//
return (this.age);
};
var person1 = new SubType("Oliver",18);
var person2 = new SubType("Troy",24);
person1.colors.pop();
console.log(person1.colors);
console.log(person2.colors);
console.log(person1.sayName() + person1.sayAge());
console.log(person2.sayName() + person2.sayAge());
/*
[Log] ["Blue", "Red"] (repetition.html, line 255)
[Log] ["Blue", "Red", "Black"] (repetition.html, line 256)
[Log] Oliver18 (repetition.html, line 257)
[Log] Troy24 (repetition.html, line 258)
*/
最も一般的な方法.もう一つ例を挙げますfunction People(name,age){
this.name = name;
this.age = age;
this.friends = [];
}
People.prototype.friendsList = function(){
document.write(this.friends.toString());
};
function Person(name,age,color,job){
People.call(this,name,age);
this.color = color;
this.job = job;
}
Person.prototype = new People();
Person.prototype.constructor = Person;
Person.prototype.sayInfo = function(){
document.write(this.name + this.age + this.color + this.job);
};
var person1 = new Person("Oliver",18,"yellow","Hero");
person1.friends.push("Alice");
person1.sayInfo(); //Oliver18yellowHero
person1.friendsList(); //Alice
var person2 = new Person("Troy",24,"White","Fighter");
person2.friends.push("Oliver","Islan");
person2.sayInfo(); //Troy24WhiteFighter
person2.friendsList(); //Oliver,Islan
普段はこの方法で十分です.また、
function Cars(name){
this.name = name;
this.hasColor = ["blue","black"];
}
Cars.prototype.sayName = function(){
console.log(this.name);
};
function Car(name,color){
Cars.call(this,name);
this.color = color;
}
Car.prototype = new Cars();
Car.prototype.constructor = Car;
Car.prototype.sayColor = function(){
console.log(this.color);
};
var benz = new Car("Benz-C200","Black");
benz.hasColor.push("red");
benz.sayName();
benz.sayColor();
console.log(benz.hasColor);
var benz2 = new Car("Benz-C180","White");
benz2.hasColor.push("white");
benz2.sayName();
benz2.sayColor();
console.log(benz2.hasColor);
/*
[Log] Benz-C200 (repetition.html, line 309)
[Log] Black (repetition.html, line 319)
[Log] ["blue", "black", "red"] (repetition.html, line 325)
[Log] Benz-C180 (repetition.html, line 309)
[Log] White (repetition.html, line 319)
[Log] ["blue", "black", "white"] (repetition.html, line 330)
*/
作成対象と継承対象を組み合わせて比較してみましょう.重要です
重要です
重要です
// -
function Person(name,age){
this.name = name;
this.age = age;
this.friendsList = ["Alice","Islan"];
}
Person.prototype.friends = function(){
console.log(this.friendsList.toString());
};
var person1 = new Person("Oliver",18);
var person2 = new Person("Troy",24);
person1.friendsList.pop();
person1.friends(); //Alice
person2.friends(); //Alice,Islan
// -
function Person(name,age){
this.name = name;
this.age = age;
this.friendsList = ["Alice","Islan"];
}
Person.prototype.friends = function(){
console.log(this.friendsList.toString());
};
function Info(name,age,job){
Person.call(this,name,age);
this.job = job;
}
Info.prototype = new Person();
Info.prototype.constructor = Info;
Info.prototype.sayJob = function(){
console.log(this.job);
};
var person1 = new Info("Oliver",18,"Master");
var person2 = new Info("Troy",24,"Hero");
person1.friendsList.pop();
person1.friends(); //Alice
person2.friends(); //Alice,Islan
person1.sayJob(); //Master
person2.sayJob(); //Hero
対照的に、継承属性は主にcallオペレータによる超型構造関数伝達パラメータに適用されていることが分かります.継承方法は字面量文法を使ってはいけません.以上
プロトタイプ継承
通常は一つの対象を他の対象と同じように維持したい場合、原型式継承は完全に可能です.対応する参照タイプの値の属性を共有します.
文法は:
function object(o){
function F(){};
F.prototype = o;
return new F();
}
例えば:function object(o){
function F(){};
F.prototype = o;
return new F();
}
var person = {
name: "Oliver",
friends: ["Alice","Islan"]
};
var anotherPerson = object(person);
anotherPerson.name = "Troy";
anotherPerson.friends.push("Ellen");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Ellen";
yetAnotherPerson.friends.push("Troy","Oliver");
console.log(person.friends);
また、function object(o){
function F(){};
F.prototype = o;
return new F();
}
var person = {
name: "Oliver",
friends: ["Alice","Islan"]
};
var anotherPerson = object(person);
anotherPerson.name = "Troy";
anotherPerson.friends.push("Oliver");
console.log(person.friends);["Alice", "Islan", "Oliver"]
この方法は比較的簡単で,personとanothersonに類似した参照型の値の属性を維持し共有させたいだけである.寄生式継承(関数多重ができず効率が低下する)
パッケージの継承プロセスの関数を作成します.
function createAnotherObj(obj){
var clone = obj;
clone.sayHi = function(){
console.log("hi");
};
return clone;
}
var person = {
name: "Troy",
friends: ["Alice"]
};
var anotherObj = createAnotherObj(person);
anotherObj.sayHi();
anotherObj.name = "Oliver";
anotherObj.friends.push("Ellen");
console.log(person.friends);
console.log(anotherObj.friends); //
寄生結合式継承(望ましい継承モデル)基本的なロジックはまず超タイプのプロトタイプのコピーを作成します.コピーにconstructor属性を追加します.最後に副本をサブタイプの原型に割り当てます.例えば:
function inheritPrototype(SubType,SuperType){
var prototype = Object(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
}
function SuperType(name){
this.name = name;
this.color = ["red","yellow"];
}
SuperType.prototype.list = function(){
console.log(this.color.toString());
};
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayName = function(){
console.log(this.name);
};
var type1 = new SubType("Oliver",18);
var type2 = new SubType("Troy",24)
type2.color.pop();
type1.list(); //red,yellow
type2.list(); //red
このようなモードをよく使うべきで、比較的に完備しています.