Antworten auf deine Fragen:
Neues Thema erstellen

JavaScript abstrakte Klasse

Fragen über Fragen die bei Vererbung und abstrakten Klassen auftreten...

Frage 1:
- Ich habe bereits diverse Problem mit den Möglichen Schreibweisen von Funktionen bekommen, als ich abstrakte "Klassen"
(die ja keine sind) realisieren wollte, sowie Vererbung.
Wo ist der Unterschied zwischen:
a.) var a = new function()
b.) var a = function()
c) function a()

Frage 2:
Warum vererbe ich nicht direkt eine Klasse mit className.Extension, sondern mit ClassName.prototype.Extension?

Frage 3:
Was hat es mit dem "Konstruktor" in JS auf sich? Ich höre immer wieder jede Funktion ist ein Konstruktor. Das bringt mich
aus dem Konzept, weil ich nur PHP-Constructors kenne und das ist eine magische Funktion.

Ich habe ein Ziel, doch möchte natürlich auch verstehen wieso. Ich habe eine Abstrakte Klasse und eine Klasse die diese ergänzen soll,
sprich im Nachhinein die Methoden der abstrakten Klasse aufrufen kann. Mein Beispiel funktioniert leider nicht:
Code:
// global namespace declaration
var ns = {};

// file one
(function(){
  ns.base = function(){
  // logic...
  };
})();

// file two
(function(){
  ns.base.prototype.child = function(){
  // logic...
  };
})();
Kann mir das jemand in eigenen Worten erklären?
 

afr0kalypse

Allwissendes Karmameerschweinchen!

Zu Frage 1
a: habe ich so noch nie gesehen. Vielleicht verwechselst du das mit einem Konstruktor?
Beispiel:
Code:
function Konstruktor() {
...
}
var a = new Konstruktor();
b: Erzeugt eine Referenz einer anonymen Funktion auf eine Variable
c: Erzeugt eine OOP ähnliche private Funktion

Zu 2. und 3. oder besser gesagt 1, 2 und 3 empfehle ich dir Peter Kroppf.
http://www.peterkropff.de/site/javascript/oop.htm
Ist einfach und verständlich erklärt. Dort werden auch genau deine Fragen arbarbeitet.
 

mindraper

me[code].Java(Script)

moinsen,

der großteil der verwirrung kommt wohl daher, dass javascript per se keine klassen besitzt :)

<tl;dr>

in javascript gibt es keine klassen in dem sinne, wie sie in anderen sprachen (bsplw. php, python, ruby, ...) existieren, statt dessen wurde eine art vererbung über metaobjekte implementiert. für die erklärung müssen jedoch ein paar begriffe definiert werden.

constructor
als constructor wird eine funktion bezeichnet, die in verbindung mit dem "new" keyword eine neue instanz (quasi ein "konkretes objekt") einer "klasse" bzw. eines metaobjektes (quasi ein "theoretisches objekt") erstellt, das konzept ist aus den meisten programmiersprachen bekannt.

im fall von javascript bewirkt das "new" keyword zusätzlich, dass der gültigkeitsbereich vom globalen kontext (auch "global scope") für die dauer der ausführung des constructors an die neue instanz des metaobjektes gebunden wird. das bedeutet, innerhalb eines constructors zeigt die (magische) variable "this" auf die neue instanz, sofern das "new" keyword ebenfalls in verbindung mit dem constructor genutzt wurde – ohne "new" zeigt "this" im constructor auf das globale objekt (im browser also das window objekt)!

tipp: die folgenden beispiele können in der konsole des browsers ausgegeben werden. alle modernen browser haben eine einfache konsole in den jeweils eigenen developer-tools installiert. im google chrome beispielsweise machst du einfach einen rechtsklick auf eine neue, leere seite und wählst im kontextmenü den punkt "element untersuchen". In den erscheinenden developer-tools wählst du den reiter "Console" aus. das vorgehen ist für beinahe alle browser identisch, für den IE musst du allerdings (meines wissens nach) die taste "F12" drücken, damit die developer-tools erscheinen. möglicherweise gibt es allerdings auch dort mittlerweile einen eintrag im kontextmenü.
das debuggen über diese tools ist wesentlich einfacher, als das dauernde nutzen von alert und erlaubt auch die nutzung von "mächtigeren" tools wie dem debugger statement. eine einführung würde jedoch den rahmen dieser antwort bei weitem sprengen :)


zu verdeutlichung (javascript, php-modus wg. syntax-highlighting):
PHP:
// globaler kontext, this verweist auf
// das globale objekt (im browser: window)
var globalContext = this;

// entweder "local" oder "global",
// siehe erklärung im constructor
var namedContext;

// beispiel constructor, per konvention in UpperCamelCase notiert
var Ctx = function () {
    // testet den kontext zu zeit der ausführung,
    // gibt "global" für globalen kontext,
    // sonst "local"
    return (this === globalContext) ? 'global' : 'local';
}

// ohne "new" keyword, der kontext innerhalb
// des constructors verweist auf das globale objekt
namedContext = Ctx();
console.log(namedContext); // => in konsole: "global"

// mit "new" keyword, der kontext innerhalb des
// constructors verweist auf eine neue CtxTest-instanz
namedContext = new Ctx();
console.log(namedContext); // => in konsole: "local"

mit hilfe von "new" und einem constructor können also neue objekte erzeugt werden. der constructor ist dabei eine möglichkeit, auf der neuen instanz einige initiale eigenschaften zu definieren oder initial benötigte methodenaufrufe von klassenmethoden auszuführen. das hört sich kompliziert an, ist im grunde aber ganz einfach:

PHP:
// constructor definition um eine neue
// "klasseninstanz" bzw. um ein neues,
// konkretes objekt aus einem metaobjekt
// zu erstellen

// der constructor erstellt neue, konkrete
// objekte vom metaobjekt "Person". die
// direkte vererbungslinie ist:
// instanz<Person> --- erbt von ---> metaobjekt<Person>
var Person = function (firstname, lastname, birthday) {
    this.fname = firstname;
    this.lname = lastname;
    this.dateOfBirth = new Date(birthday);

    this.calculateAge();
}

mit diesem constructor und dem "new" keyword können neue instanzen des metaobjektes "Person" erstellt werden (auch: instanziert). es können drei argumente an den constructor übergeben werden, die dann zur ausführungszeit zur verfügung stehen (firstname, lastname, birthday).
der neuen instanz werden diese drei argumente als eigenschaften (sog. properties) angehängt. das passiert in den zeilen "this.fname..." bis einschließlich "this.dateOfBirth...".

wenn du das beispiel in der konsole laufen lässt, dann wirft diese einen fehler (berechtigterweise) der sagt:

PHP:
TypeError: undefined is not a function

das passiert, weil zuletzt mit "this.calculateAge()" die (gleichnamige) methode der instanz bzw. der klasse/des metaobjektes aufgerufen wird. dieses ist jedoch noch nicht definiert worden. dafür wird das prototype objekt benötigt.

prototype/das metaobjekt
über die prototype eigenschaft eines constructors wird das mit ihm erstellte konkrete objekt über ein metaobjekt definiert. ein metaobjekt dient als blaupause/bauplan/schablone/vorlage für neue instanzen eines konkreten objektes, das mit dem (theoretisch: einem) ihm zugewiesenen constructor erstellt wird.

du kannst dir auch einen stempel vorstellen, mit dem neue abdrücke des gleichen musters/der gleichen vorlage gedruckt werden. die teile des stempels hätten ihre (ungefähren) javascript entsprechungen also so:
  • Prototype-Objekt/Metaobjekt = Schablone
  • Constructor = Stempelmechanismus
  • Instanz = Gedrucktes Bild / Abdruck der Schablone

beispiel:
PHP:
// annahme: es sollen instanzen der klasse/des
// metaobjektes "Thing" erstellt werden. jede instanz
// soll die methoden "getCurrent" und "setCurrent"
// besitzen. verwaltet wird ein einfacher primitiver wert.

// dies ist das metaobjekt
var metaThing = {
    current: null, // speicherplatz für den verwalteten wert
    setCurrent: function (newValue) {
        // setzt den aktuellen wert auf "newValue"
        this.current = newValue;
    },
    getCurrent: function () {
        // gibt den aktuellen wert zurück
        return this.current;
    }
}

// das ist der constructor
var Thing = function (initialValue) {
    // speichert den initialen wert in der konkreten instanz
    this.current = initialValue;
}

// weist dem "Thing" constructor als bauplan
// das metaobjekt "metaThing" zu
Thing.prototype = metaThing;

// erstellt eine neue instanz von "Thing"
var concreteThing = new Thing(1);

console.log(concreteThing.getCurrent()); // => 1

concreteThing.setCurrent('howdy');
console.log(concreteThing.getCurrent()); // => 'howdy'

console.log(concreateThing); // *
// => Thing {
//    current: 'howdy',
//    ...
//    prototype: {
//        current: null,
//        setCurrent: function (newValue) { ... },
//        getCurrent: function () { ... },
//        ...
//        prototype: Object
//    }
// }
* die letzte ausgabe ist zum einfacheren verständnis schematisiert dargestellt. die drei punkte stehen für ausgelassene eigenschaften. die reale darstellung variiert je nach genutztem browser.

wie du an der ausgabe sehen kannst, ist "concreteThing" eine instanz des metaobjektes "Thing", dessen konkreter wert "current" auf "1" bzw. "howdy" gesetzt wurde. der wert "current" des metaobjektes ist nach wie vor null.

da auf der instanz jedoch die methoden "setCurrent" und "geCurrent" nicht definiert sind, wieso wird dann kein fehler geworfen, wenn <instanz>.getCurrent() aufgerufen wird?

der grund ist, dass bei einem aufruf einer methode auf einer instanz zuerst von der javascript engine nachgeschaut wird, ob die methode auf der instanz selbst existiert. ist dies nicht der fall, wird nachgeschaut, ob die methode auf dem prototypen (dem metaobjekt) der instanz definiert ist. ist auch dies nicht der fall, wandert die engine die kette an prototypen entlang bis zum finalen metaobjekt (das "Object" objekt). wird auf diesem weg entlang der prototypen kette eine passende methode gefunden, wird diese auf der instanz ausgeführt ("this" zeigt also in diesem moment auf die instanz), wird keine passende methode gefunden wirft die javascript engine einen fehler (siehe oben).

man stelle sich eine kette vor, die wie perlen an der schnur abgelaufen wird (nicht ausführbar in konsole!):
Code:
<instanz>.methode() --> auf instanz vorhanden? --- ja ---> ausführen
                                        |
                                      nein ---> auf prototyp vorhanden? --- ja ---> ausführen
                                                            |
                                                           ...
                                                            |
                                                           nein ---> ...terminiere

du kannst dir vererbung in javascript also so vorstellen:
Code:
<instanz>
        |
        --- erbt von ---> metaobjekt
                              |
                              --- erbt von ---> (vorheriges metaobjekt)
                                                           |
                                                           --- erbt von ---> Object

Wird für ein constructor kein prototyp explizit definiert bzw. wird einer als constructor genutzten funktion kein explizites metaobjekt über die prototype eigenschaft zugewiesen, wird ein normales Object ({}) genutzt.

jede funktion kann ein constructor sein?
per definition kann jede funktion als constructor genutzt werden. aus dem obigen beispiel geht hervor wieso: das metaobjekt "metaThing" könnte auch einem anderen constructor als prototyp zugewiesen werden. um in javascript eine funktion als constructor zu nutzen muss dazu lediglich:
  1. das "new" keyword in verbindung mit dem aufruf des constructors genutzt werden
  2. der constructor eigenschaft prototype ein metaobjekt zugewiesen werden
beispiel:
PHP:
// ein zweiter constructor für "Thing",
// nutzt das gleiche metaobjekt als
// bauplan für neue instanzen
var Some = function (value) {
    this.current = value;
}

// alternativ: Some.prototype = metaThing
Some.prototype = Thing.prototype;

im anschluss können über beide constructor funktionen neue instanzen vom metaobject "metaThing" erstellt werden. der unterschied zwischen beiden ist, dass sie unterschiedliche constructor funktionen besitzen, ansonsten ist ihr innerer aufbau identisch.

zu den gezeigten varianten a), b) und c)
diese drei zeigen unterschiedliche einsatzzwecke und/oder auch definitionsmöglichkeiten von funktionen in javascript.

a) einsatz einer anonymen (nicht benannten) funktion als constructor
PHP:
var concrete = new function () { ... }
je nach inhalt des funktionskörpers (auch: function body) würde concrete unterschiedlich aussehen. wie oben gesagt, im einfachsten fall ein übliches Object objekt. eine variante in form eines sog. "design patterns" wäre das (revealing) module pattern:
PHP:
var concrete = (function () { ... })();
eine (zugegeben bescheurte aber funktionierende) andere variante:
PHP:
var concrete = new (new Function( ... ))();

b) weist der variablen "a" entweder den rückgabewert einer anonymen funktion (unwarscheinlicher) oder die funktion selbst zu (warscheinlicher). leider zeigt dein beispiel nicht, welche der möglichkeiten zutrifft. daher:

1) trifft vermutung eins zu (rückgabewert)
PHP:
var a = function () { ... } ();
dann enthält "a" den rückgabewert oder "undefined" & der programmierer hat m. e. nach einen nicht-so-tollen stil, weil nicht auf anhieb ersichtlich ist, dass dies funktion direkt ausgeführt wird (immediatly invoked function expression).

2) trifft vermutung zwei zu (funktions definition)
PHP:
var a = function () { ... };
dann enthält "a" die referenz auf eine anonyme funktion. die funktion kann über den aufruf von "a" ausgeführt werden.

c) zeigt einen syntaxerror ;) .spaß beiseite, gezeigt wird die definition einer benannten funktion "a".

PHP:
function a () { ... }




hoffe das hilft
 
Zuletzt bearbeitet:
Bilder bitte hier hochladen und danach über das Bild-Icon (Direktlink vorher kopieren) platzieren.
Antworten auf deine Fragen:
Neues Thema erstellen

Willkommen auf PSD-Tutorials.de

In unseren Foren vernetzt du dich mit anderen Personen, um dich rund um die Themen Fotografie, Grafik, Gestaltung, Bildbearbeitung und 3D auszutauschen. Außerdem schalten wir für dich regelmäßig kostenlose Inhalte frei. Liebe Grüße senden dir die PSD-Gründer Stefan und Matthias Petri aus Waren an der Müritz. Hier erfährst du mehr über uns.

Stefan und Matthias Petri von PSD-Tutorials.de

Nächster neuer Gratisinhalt

03
Stunden
:
:
25
Minuten
:
:
19
Sekunden

Neueste Themen & Antworten

Flatrate für Tutorials, Assets, Vorlagen

Zurzeit aktive Besucher

Statistik des Forums

Themen
118.616
Beiträge
1.538.358
Mitglieder
67.536
Neuestes Mitglied
QuestionMark
Oben