Heim  >  Artikel  >  Web-Frontend  >  Sechs Möglichkeiten zur Implementierung der Vererbung in JavaScript

Sechs Möglichkeiten zur Implementierung der Vererbung in JavaScript

黄舟
黄舟Original
2017-10-23 09:44:211409Durchsuche

Beschreibung der Vererbung in JavaScript:

Viele objektorientierte Sprachen unterstützen zwei Vererbungsmethoden: Schnittstellenvererbung und Implementierungsvererbung. Die Schnittstellenvererbung erbt nur Methodensignaturen, während die Implementierungsvererbung die tatsächlichen Methoden erbt. In JavaScript kann die Schnittstellenvererbung nicht implementiert werden, da die Funktion keine Signatur hat. Es wird jedoch nur die Implementierungsvererbung unterstützt, und die Implementierungsvererbung wird hauptsächlich über die Prototypenkette erreicht.

Lassen Sie uns zunächst die Beschreibung der Prototypenkette im offiziellen Dokument zitieren: Die Grundidee besteht darin, Prototypen zu verwenden, um einem Referenztyp die Eigenschaften und Methoden eines anderen Referenztyps erben zu lassen. Um dieses Konzept zu verstehen, müssen wir zunächst die Beziehung zwischen Konstruktoren, Prototypen und Instanzen klären: Jeder Konstruktor (sofern es sich um eine Funktion handelt) verfügt über ein Prototypattribut, das auf ein Objekt zeigt (dieses Objekt ist das Prototypobjekt des Konstruktors). ); das Prototypobjekt (solange es ein Objekt ist), es gibt ein Konstruktorattribut, das auf einen Konstruktor zeigt, und die Instanz enthält einen internen Zeiger [[Prototyp]], der auf das Prototypobjekt zeigt; Um es ganz klar auszudrücken: Der Aufbau der Prototypenkette wird erreicht, indem eine Instanz eines Typs dem Prototyp eines anderen Konstruktors zugewiesen wird. Auf diese Weise kann der Subtyp auf alle Eigenschaften und Methoden zugreifen, die für den Supertyp definiert sind. Jedes Objekt verfügt über ein eigenes Prototypobjekt, das das Prototypobjekt als Vorlage verwendet, um Eigenschaften und Methoden vom Prototypobjekt zu erben. Das Prototypobjekt kann auch einen eigenen Prototyp haben und Schicht für Schicht Eigenschaften und Methoden von diesem erben Die Beziehung wird als Prototypenkette bezeichnet und erklärt, warum ein Objekt über Eigenschaften und Methoden verfügt, die für andere Objekte definiert sind.


Sechs Möglichkeiten, Vererbung in Javascript zu implementieren:

Prototypenkette )


4. Prototypische Vererbung


5. Parasitäre Vererbung


6. Parasitäre kombinierte Vererbung (Kombination aus kombinierter Vererbung und parasitärer Vererbung)


1. Prototypenkette

// 实现原型链的一种基本模式
function SuperType(){
            this.property = true;
}
SuperType.prototype.getSuperValue = function(){
            return this.property;
};
function SubType(){
            this.subproperty = false;
}

// 继承,用 SuperType 类型的一个实例来重写 SubType 类型的原型对象
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
            return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue());     // true

PS: SubType erbt SuperType, und die Vererbung wird erreicht, indem eine Instanz von SuperType erstellt und die Instanz dem Prototyp von SubType zugewiesen wird. Der Kern der Implementierung besteht darin, das Prototypobjekt des Untertyps zu überschreiben und durch eine Instanz des neuen Typs zu ersetzen. Das neue Prototypobjekt des Untertyps verfügt über eine interne Eigenschaft [[Prototype]], die auf den SuperType-Prototyp verweist, und einen vom SuperType-Prototyp geerbten Eigenschaftskonstruktor, der auf den SuperType-Konstruktor verweist. Die endgültige Prototypkette sieht folgendermaßen aus: Die Instanz zeigt auf den Prototyp von SubType, der Prototyp von SubType zeigt auf den Prototyp von SuperType und der Prototyp von SuperType zeigt auf den Prototyp von Object (der Standardprototyp aller Funktionen ist eine Instanz von Object). , sodass der Standardprototyp einen internen Zeiger auf Object.prototype enthält.
Nachteile der Prototypenkette:
1. Wenn die Vererbung durch Prototypen implementiert wird, wird der Prototyp tatsächlich zu einer Instanz eines anderen Typs. Dadurch werden die ursprünglichen Instanzattribute natürlich zu den aktuellen Prototypattributen und werden von allen Instanzen gemeinsam genutzt. Dies ist so zu verstehen: Die Instanzeigenschaften des im Supertyp-Konstruktor definierten Referenztypwerts werden zu Prototypeigenschaften des Subtyp-Prototyps und werden von allen Subtyp-Instanzen gemeinsam genutzt.
2. Beim Erstellen einer Instanz eines Untertyps können keine Parameter an den Konstruktor des Obertyps übergeben werden.

2. Ausleihen von Konstruktoren (auch Fake-Objekte oder klassische Vererbung genannt)

// 在子类型构造函数的内部调用超类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上
function SuperType(){
            // 定义引用类型值属性
            this.colors = ["red","green","blue"];
}
function SubType(){
            // 继承 SuperType,在这里还可以给超类型构造函数传参
            SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("purple");
alert(instance1.colors);     // "red,green,blue,purple"

var instance2 = new SubType();
alert(instance2.colors);     // "red,green,blue"

PS: Durch die Verwendung der apply()- oder call()-Methode sind wir tatsächlich der SuperType Der Konstruktor wird im Kontext der zu erstellenden SubType-Instanz aufgerufen. Dadurch wird der gesamte in der SuperType()-Funktion definierte Objektinitialisierungscode für das neue SubType-Objekt ausgeführt. Infolgedessen verfügt jede Instanz von SubType über eine eigene Kopie der Colors-Eigenschaft.
Der Vorteil des Ausleihens eines Konstruktors besteht darin, dass zwei Probleme der Vererbung der Prototypkettenimplementierung gelöst werden. Der Nachteil des Ausleihens eines Konstruktors besteht darin, dass alle Methoden im Konstruktor definiert sind, sodass eine Wiederverwendung von Funktionen nicht erreicht werden kann. Darüber hinaus sind im Prototyp des Supertyps definierte Methoden für Untertypen nicht sichtbar, sodass alle Typen nur das Konstruktormuster verwenden können.

3. Kombinationsvererbung (auch pseudoklassische Vererbung genannt)

// 将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。
function SuperType(name){
            this.name = name;
            this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
            alert(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(){
            alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors);      // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("tom",34);
alert(instance2.colors);      // "red,green,blue"
instance2.sayName();
instance2.sayAge();

PS: Kombinationsvererbung vermeidet die Mängel von Prototypketten und geliehenen Konstruktoren, integriert deren Vorteile und wird zum Standard JavaScript Das am häufigsten verwendete Vererbungsmuster. Darüber hinaus können mithilfe des Operators „instanceof“ und der Methode „isPrototype()“ auch Objekte identifiziert werden, die auf der Grundlage kompositorischer Vererbung erstellt wurden. Allerdings hat es auch seine eigenen Mängel. Das größte Problem besteht darin, dass der Supertyp-Konstruktor unabhängig von den Umständen zweimal aufgerufen wird: einmal beim Erstellen des Subtyp-Prototyps und einmal innerhalb des Subtyp-Konstruktors.

4. Prototypische Vererbung

// 借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
1、自定义一个函数来实现原型式继承
function object(o){
            function F(){}
            F.prototype = o;
            return new F();
}

PS: Erstellen Sie innerhalb der Funktion object() zunächst einen temporären Konstruktor und verwenden Sie dann das eingehende Objekt als diesen Konstruktor Funktion und gibt schließlich eine neue Instanz dieses temporären Typs zurück. Im Wesentlichen führt object() eine flache Kopie des übergebenen Objekts aus.
2. Verwenden Sie die Methode Object.create(), um die prototypische Vererbung zu implementieren. Diese Methode akzeptiert zwei Parameter: ein Objekt, das als Prototyp des neuen Objekts verwendet wird, und ein Objekt, um zusätzliche Eigenschaften für das neue Objekt zu definieren. Diese Methode funktioniert genauso wie die Methode object(), wenn ein Parameter übergeben wird.
Wenn der zweite Parameter übergeben wird, überschreiben alle angegebenen Eigenschaften die gleichnamigen Eigenschaften des Prototypobjekts.

var person = {
            name: "luochen",
            colors: ["red","green","blue"]
}; 
var anotherPerson1 = Object.create(person,{
            name: {
                    value: "tom"
            }
});
var anotherPerson2 = Object.create(person,{
            name: {
                    value: "jerry"
            }
});
anotherPerson1.colors.push("purple");
alert(anotherPerson1.name);     // "tom"
alert(anotherPerson2.name);     // "jerry"
alert(anotherPerson1.colors);    // "red,green,blue,purple"
alert(anotherPerson2.colors);    // "red,green,bule,purple";

PS: Wenn Sie nur möchten, dass ein Objekt einem anderen Objekt ähnelt, ist die prototypische Vererbung durchaus möglich. Der Nachteil ist jedoch: Eigenschaften, die Referenztypwerte enthalten, teilen sich immer den entsprechenden Wert.

5. Parasitäre Vererbung

// 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象
function createPerson(original){
            var clone = Object.create(original);   // 通过 Object.create() 函数创建一个新对象
            clone.sayGood = function(){              // 增强这个对象
                        alert("hello world!!!");
            };
            return clone;                                      // 返回这个对象 
}

PS: Parasitäre Vererbung ist auch ein nützliches Muster, wenn hauptsächlich Objekte anstelle von benutzerdefinierten Typen und Konstruktoren berücksichtigt werden. Der Nachteil dieses Modus besteht darin, dass Funktionen nicht wiederverwendet werden können.

6. Parasitäre kombinierte Vererbung

// 通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
function SuperType(name){
            this.name = name;
            this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
            alert(this.name);
};
function SubType(name,age){
            SuperType.call(this,name);
            this.age = age;
}
// 创建超类型原型的一个副本
var anotherPrototype = Object.create(SuperType.prototype);
// 重设因重写原型而失去的默认的 constructor 属性
anotherPrototype.constructor = SubType;
// 将新创建的对象赋值给子类型的原型
SubType.prototype = anotherPrototype;

SubType.prototype.sayAge = function(){
            alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors);      // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("tom",34);
alert(instance2.colors);      // "red,green,blue"
instance2.sayName();
instance2.sayAge();

PS: Die hohe Effizienz dieses Beispiels spiegelt sich darin wider, dass der SuperType-Konstruktor nur einmal aufgerufen wird und daher kein SubType erforderlich ist .prototype. Erstellen Sie unnötige, redundante Attribute. Gleichzeitig bleibt die Prototypenkette unverändert; der Instanzoperator und die Methode isPrototype() können daher normal verwendet werden.

Das obige ist der detaillierte Inhalt vonSechs Möglichkeiten zur Implementierung der Vererbung in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn