JavaScript-Vererbung: Object.create vs new

123

Was ist in JavaScript der Unterschied zwischen diesen beiden Beispielen:

Voraussetzung:

function SomeBaseClass(){
}

SomeBaseClass.prototype = {
    doThis : function(){
    },

    doThat : function(){
    }
}

Vererbungsbeispiel A mit Object.create:

function MyClass(){
}

MyClass.prototype = Object.create(SomeBaseClass.prototype);

Vererbungsbeispiel B mit dem neuen Schlüsselwort

function MyClass(){
}

MyClass.prototype = new SomeBaseClass();

Beide Beispiele scheinen dasselbe zu tun. Wann würden Sie einen über den anderen wählen?

Eine zusätzliche Frage: Betrachten Sie den Code im folgenden Link (Zeile 15), in dem ein Verweis auf den eigenen Konstruktor der Funktion im Prototyp gespeichert ist. Warum ist das nützlich?

https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js

Auszug (wenn Sie den Link nicht öffnen möchten):

THREE.ImageLoader.prototype = {

    constructor: THREE.ImageLoader
}
ChrisRich
quelle
23
Warum zum Teufel ist das als Duplikat markiert!?! Die andere Frage und die Antworten werden nicht einmal erwähnt Object.create. Dies ist ein Fehler und sollte erneut geöffnet werden.
Scott Rippey
2
Wenn überhaupt, ist es ein Duplikat von stackoverflow.com/questions/4166616/…
Scott Rippey
1
13 Stimmen zu diesem Kommentar und immer noch nicht wieder geöffnet ..?!
TJ

Antworten:

111

In Ihrer Frage haben Sie erwähnt, dass Both examples seem to do the same thinges überhaupt nicht wahr ist, weil

Dein erstes Beispiel

function SomeBaseClass(){...}
SomeBaseClass.prototype = {
    doThis : function(){...},
    doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);

In diesem Beispiel erben Sie nur, SomeBaseClass' prototypeaber was ist, wenn Sie eine Eigenschaft in Ihrem SomeBaseClassLike haben?

function SomeBaseClass(){ 
    this.publicProperty='SomeValue'; 
}

und wenn du es gerne benutzt

var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);​

Das objObjekt hat keine publicPropertyEigenschaft wie in diesem Beispiel .

Dein zweites Beispiel

MyClass.prototype = new SomeBaseClass();

Es führt die constructorFunktion aus, erstellt eine Instanz des SomeBaseClassgesamten SomeBaseClassObjekts und erbt es . Also, wenn Sie verwenden

    var obj=new MyClass();
    console.log(obj.publicProperty); // SomeValue
    console.log(obj);​

In diesem Fall steht seine publicPropertyEigenschaft auch dem objObjekt wie in diesem Beispiel zur Verfügung .

Da das Object.createin einigen alten Browsern nicht verfügbar ist, können Sie es in diesem Fall verwenden

if(!Object.create)
{
    Object.create=function(o){
        function F(){}
        F.prototype=o;
        return new F();
    }
}

Der obige Code fügt nur Object.createFunktionen hinzu , wenn diese nicht verfügbar sind, sodass Sie die Object.createFunktion verwenden können. Ich denke, der obige Code beschreibt, was Object.createtatsächlich funktioniert. Hoffe, es wird irgendwie helfen.

Das Alpha
quelle
6
Hallo Scheich. Vielen Dank für Ihre Bemühungen. Ja, der Unterschied besteht darin, dass der Konstruktor im zweiten Beispiel ausgeführt wird, nicht jedoch im ersten. (was in meinem Fall wünschenswert ist). In Bezug auf die undefinierte öffentliche Eigenschaft, die nicht von der Super-Implementierung geerbt wird, müssen Sie nur Super im Konstruktor des Kindes aufrufen: SomeBaseClass.call (this). Überprüfen Sie diese Geige: jsfiddle.net/NhQGB
ChrisRich
Ich habe nach einer supereinfachen Möglichkeit zur ordnungsgemäßen Vererbung in JS gesucht, ohne Bibliotheken / Frameworks zu verwenden. Ich denke, dieses Beispiel (in meiner obigen Geige) ist der beste Ansatz für moderne Browser. Vielleicht könnte die Polyfill Object.Create Unterstützung für ältere Browser hinzufügen?
ChrisRich
Um es zusammenzufassen: Wenn Sie .prototype = new ausführen, erben Sie alle Werte, die Sie diesem in der Basisklasse zugewiesen haben, und wenn Sie object.create ausführen, erben Sie NUR das, was sich auf dem Prototyp in der Basisklasse befindet, richtig?
Davidjnelson
Bedeutet dies "MyClass.prototype = new SomeBaseClass ()", dass eine neue Instanz von SomeBaseClass erstellt wird, wenn die Instanz von MyClass noch nicht erstellt wurde?
Nein, nur wenn Sie das Hauptobjekt erstellen, wird der Prototyp darauf eingestellt SomeBaseClass.
Die Alpha
39

Beide Beispiele scheinen dasselbe zu tun.

Das stimmt in deinem Fall.

Wann würden Sie einen über den anderen wählen?

Wenn SomeBaseClassein Funktionskörper vorhanden ist, wird dieser mit dem newSchlüsselwort ausgeführt. Dies ist normalerweise nicht beabsichtigt - Sie möchten nur die Prototypenkette einrichten. In einigen Fällen kann es sogar zu schwerwiegenden Problemen kommen, da Sie tatsächlich ein Objekt instanziieren , dessen Variablen mit privatem Bereich von allen MyClassInstanzen gemeinsam genutzt werden, da sie dieselben privilegierten Methoden erben. Andere Nebenwirkungen sind denkbar.

Sie sollten es also generell vorziehen Object.create. In einigen älteren Browsern wird es jedoch nicht unterstützt. Aus diesem Grund sehen Sie den newAnsatz viel zu häufig, da er oft keinen (offensichtlichen) Schaden anrichtet. Schauen Sie sich auch diese Antwort an .

Bergi
quelle
Dies ist die beste Antwort, gut erklärt
spex
8

Der Unterschied wird offensichtlich, wenn Sie Object.create()ihn bestimmungsgemäß verwenden. Tatsächlich verbirgt es das prototypeWort vollständig aus Ihrem Code , es erledigt den Job unter der Haube. Mit Object.create()können wir gehen wie

var base =  {
    doThis : function(){
    },

    doThat : function(){
    }
};

Und dann können wir andere Objekte daraus erweitern / erben

var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally

Dies ist also ein anderes Konzept, eine "objektorientiertere" Art der Vererbung. Es gibt zum Beispiel keine "Konstruktorfunktion", die standardmäßig verwendet wird Object.create(). Aber Sie können natürlich auch eine selbst definierte Konstruktorfunktion innerhalb dieser Objekte erstellen und aufrufen .

Ein Argument für die Verwendung Object.create()ist, dass es möglicherweise natürlicher aussieht, andere Objekte zu mischen / * zu erben *, als die Standardmethode von Javascripts zu verwenden .

jAndy
quelle
7
Object.createkann den klassischen Ansatz nicht wirklich ersetzen, newwenn eine Konstruktorfunktion benötigt wird
Bergi
1
Es kann definitiv @Bergi. Schauen Sie sich diesen Blog-Beitrag an: davidwalsh.name/javascript-objects-deconstruction . Sie können ein Initialisierungsobjekt auch als zweiten Parameter an Object.create () übergeben.
LocalPCGuy
@LocalPCGuy: Nein, das kann es nicht, da Object.createkeine Funktion aufgerufen wird, die zum Erstellen von Abschlüssen erforderlich wäre. Natürlich Object.createkönnen Sie mit eine initMethode auf Ihre Objekte setzen und diese sofort aufrufen, und sie wird möglicherweise sogar zurückgegeben, thissodass Sie eine präzise Syntax erhalten - aber warten Sie, das ist dann ein Konstruktor.
Bergi
1
Das Aufrufen einer init-Funktion funktioniert ähnlich wie ein Konstruktor, ist jedoch kein Konstruktor. Mit dieser Methode können Sie den klassischen Ansatz genau durch Object.create ersetzen. Und das mentale Modell der Objektverknüpfung ist viel einfacher als das, das über 'neu' erstellt wurde.
LocalPCGuy
Nun, mein mentales Modell newverwendet "Objektverknüpfung", also gibt es keinen großen Unterschied. Tatsächlich gibt es nur zwei Dinge: .constructorWird aufgerufen .init, und diese Funktion hat keine .prototypeEigenschaft, die auf Ihr Prototypobjekt verweist. Der Rest ist nur Syntax - und ich ziehe new Xüber Object.create(x).init().
Bergi
0

Ich bin kein Experte für Java-Skripte, aber hier ist ein einfaches Beispiel, um den Unterschied zwischen "Object.create" und "new" zu verstehen.

Schritt 1: Erstellen Sie die übergeordnete Funktion mit einigen Eigenschaften und Aktionen.

function Person() {

this.name = 'venkat';

this.address = 'dallas';

this.mobile='xxxxxxxxxx'

}

Person.prototype.func1 = function () {

    return this.name + this.address;
}

Schritt 2: Erstellen Sie eine untergeordnete Funktion (PersonSalary), die mit dem Schlüsselwort New über die Funktion Person hinausgeht .

function PersonSalary() {
    Person.call(this);
}
PersonSalary.prototype = new Person();

PersonSalary();

Schritt 3: Erstellen Sie mit dem Schlüsselwort Object.create eine zweite untergeordnete Funktion (PersonLeaves), die über die Funktion Person hinausgeht .

function PersonLeaves() {
 Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);


PersonLeaves();

// Überprüfen Sie nun beide Prototypen der untergeordneten Funktionen.

PersonSalary.prototype
PersonLeaves.prototype

Diese beiden untergeordneten Funktionen werden mit dem Prototyp Person (übergeordnete Funktion) verknüpft und können auf dessen Methoden zugreifen. Wenn Sie jedoch eine untergeordnete Funktion mit new erstellen, wird ein brandneues Objekt mit allen übergeordneten Eigenschaften zurückgegeben, die wir nicht benötigen, und auch, wenn Sie welche erstellen Objekt oder Funktion mit "Neu" wird diese übergeordnete Funktion ausgeführt, die wir nicht sein wollen.

Hier sind die Imbissbuden

Wenn Sie nur an einige Methoden in der übergeordneten Funktion delegieren möchten und nicht möchten, dass ein neues Objekt erstellt wird, ist die Verwendung von Object.create der beste Weg.

Venkat
quelle