JavaScript Vererbung

BodyLAB

Bekanntes Mitglied
Hallo zusammen,
ich versuche gerade die Vererbung über die Konstruktor Funktionen abzubilden. Leider funktioniert das ganze nicht da die VM immer den Fehler bringt:
error: TypeError: Shape.call is not a function

Hier mal der Quellcode:
Javascript:
function Shape() {
    this.type = 'Shape';
}

function Triangle(a, b, c) {
    Shape.call(this); 
    this.type = 'Triangle';
    this.a = a;
    this.b = b;
    this.c = c;
}

Shape.prototype.getShape = function() {
    return `Das ist eine ${this.type}`;
}

Triangle.prototype.circumference = function() {
    return this.a + this.b + this.c;
}

Triangle.prototype = Shape;
Triangle.prototype.__proto__ = Shape.prototype;

function GLTriangle(a, c) {
    Triangle.call(this, a, a, c);
    this.type = 'GLTriangle';
}

GLTriangle.prototype.set = function(a) {
    this.a = a;
}

Shape ist aber doch eine Funktion wieso kommt dieser Fehler wenn man
const tri = new Triangle(1,2,3); eingibt?
Weiß das jemand und kann es mir erklären?

FireFox gibt mir zur Hilfe dieses Beispiel:
Javascript:
function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);

Dort findet er "komischerweise" die .call Methode.
 

mihe7

Top Contributor
In Zeile 21 setzt Du Triangle.prototype auf Shape. In Zeile 22 greifst Du auf Triangle.prototype.__proto__, d. h. wegen Zeile 21 auf Shape.__proto__ zu und setzt die Eigenschaft auf Shape.prototype. Shape.prototype ist aber keine Function sondern ein Objekt.

Was Du wollen würdest, wäre Zeile 21 wegzulassen. In dem Fall würdest Du Triangle.prototype.__proto__ auf Shape.prototype zeigen lassen. Tatsächlich ist __proto__ deprecated. Stattdessen soll Object.create verwendet werden, mit dem ein Prototyp basierend auf einem gegebenen Prototyp erstellt wird:

Javascript:
function Shape() {
    this.type = 'Shape';
}

function Triangle(a, b, c) {
    Shape.call(this);
    this.type = 'Triangle';
    this.a = a;
    this.b = b;
    this.c = c;
}

Triangle.prototype = Object.create(Shape.prototype);
Triangle.prototype.constructor = Triangle;

let tri = new Triangle(1,2,3);
 

BodyLAB

Bekanntes Mitglied
Und mit modernem Javascript kann man sich die ganzen Prototype spielereien auch sparen und einfach Klassen verwenden
Ja seit ES6. Mir ging es aber ja darum das ganze mit den Konstruktorfunktionen zu machen und hoffentlich dann auch zu verstehen :)


Triangle.prototype.constructor = Triangle;
Triangle ist meine Konstruktorfunktion, sagt man mit prototype.constructor, dass wenn man mittels new ein neues Objekt initialisiert das er diese Konstruktorfunktion aufrufen soll und den this Kontext etc. setzen soll.


Ich schaue mir das ganze gleich an. Hoffe die static Methoden sind dann auch noch in meiner Klasse vorhanden. Diese werden ja im Objekt gespeichert. Finde das Konzept in JS viel verwirrender als in Java. Wieso die das so machen weiß ich auch nicht :-D Hat sich wohl so entwickelt.

Für die Antworten :cool:
 

BodyLAB

Bekanntes Mitglied
so sieht es als Klasse aus:
Javascript:
"use strict"

class Shape {
    type = 'Shape';
    getShape() {
        return `Das ist eine ${this.type}`;
    }
}

class Triangle extends Shape {
    constructor(a, b, c) {
        super();
        this.type = 'Triangle';
        this.a = a;
        this.b = b;
        this.c = c;
    }
    circumference() {
        return this.a + this.b + this.c;
    }
}

class GLTriangle extends Triangle {
    constructor(a, c) {
        super(a, a, c);
        this.type = 'GLTriangle';
    }
    get b() {
        return this.a;
    }
    set b(a) {
        this.a = a;
    }
}

const shape = new Shape();
console.log(shape);
const triangle = new Triangle(4,5,3);
console.log(triangle);
console.log(triangle.circumference());
const glTriangle = new GLTriangle(12,44);
console.log(glTriangle);
console.log(glTriangle.circumference());

Der Code von oben scheint Äquivalent zu sein zur Klasse super, genau das was ich wollte. Verstehen tu ich das mit dem .prototype.constructor jetzt leider noch nicht.
 

mihe7

Top Contributor
Funktionen sind in JS auch Objekte und die prototype-Eigenschaft des Funktionsobjekts zeigt auf ein Objekt, das zunächst über zwei Eigenschaften verfügt: constructor und __proto__.

Dabei zeigt constructor auf die Funktion, die zur Erstellung neuer Objekte via new verwendet wird. Normalerweise ist das genau die deklarierte Funktion (bei function f() {} zeigt f.prototype.constructor also auf f).

Mit Object.create wird nun aber ein neuer Prototyp basierend auf einem anderen Prototypen erstellt. Dieser enthält nur die Eigenschaft __proto__ mit Verweis auf den originalen Prototypen.

Heißt also, wenn Du
Javascript:
function f() {}
function g() {}
schreibst, dann hast Du zwei Funktionsobjekte, die verkürzt so aussehen:
Javascript:
{
  name: "f",
  prototype: {
      constructor: f,
      __proto__: Function.prototype.__proto__
  }
}
Analog für g. Object.create(f.prototype) erzeugt nun ein Objekt
Javascript:
{
    __proto__: f.prototype
}
Wenn wir dieses Objekt an g.prototype zuweisen, dann sieht g verkürzt so aus:
Javascript:
{
  name: "g",
  prototype: {
    __proto__: {
        constructor: f,
        __proto__: Function.prototype.__proto__
    }  
  }
}
Rufst Du jetzt new g() auf, dann findet JS in g.prototype keine constructor-Function und sucht im nächsten Glied der Prototypenkette weiter, also in g.prototype.__proto__. Dort wird der constructor gefunden und aufgerufen, d. h. f(). Wir wollen aber, dass g() als Konstruktor verwendet wird, daher weisen wir dem Prototypen von g die entsprechende Eigenschaft zu: g.prototype.constructor = g

Wird jetzt new g() aufgerufen, wird im Prototypen von g der Konstruktor gefunden und aufgerufen -> g(). Das Objekt sieht also so aus, wie wir es haben wollen:
Javascript:
{
  name: "g",
  prototype: {
    constructor: g,
    __proto__: {
        constructor: f,
        __proto__: Function.prototype.__proto__
    }  
  }
}
Ich hoffe, vor lauter Prototypen nirgends einen größeren Schnitzer drin zu haben :)
 

BodyLAB

Bekanntes Mitglied
Leider kam ich jetzt erst dazu mir deine Antwort anzusehen.
Das ist ja echt super erklärt :) Vielen Lieben Dank ;-)

Glaube du solltest ein Buch schreiben ;-)
 

Ähnliche Java Themen

Neue Themen


Oben