• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

private Eigenschaften in class

im grunde nicht anders als bisher, nur dass du sie in den constructor als lokale variablen hängen musst.
 
Wie meinst du das?
Code:
"use strict";
class X {
   constructor() {
      var v = 100;
   }
   m() {
      return v;
   }
}
var x = new X();
alert(x.m());
So irgendwie? So hatte ich das schon versucht. Aber dann kennt die Methode m die private Eigenschaft v nicht.

(Getestet mit Google Chrome)
 
Code:
class X {
   constructor() {
      var v = 100;
   }
   this.m = function ()
   {
      return v;
   };
}
var x = new X();
alert(x.m());
 
Ich habe das jetzt auch noch erweitert mit einer getter- und einer setter-Methode:
Code:
class X {
   constructor() {
      var v = 100;
      this.getM = function() {
         return v;
      };
      this.setM = function(_v) {
         v = _v;
      };
   }
   get v() {
      return this.getM();
   }
   set v(v) {
      this.setM(v);
   }
}
var x = new X();
x.v = 200;
alert(x.v);
Schaut aber leider ziemlich kompliziert aus. Ziemlich viel zu tippen :(

Geht das vielleicht noch einfacher?
 
Ja, das war jetzt mein Fehler. Hatte vergessen zu erwähnen, dass da natürlich auch noch irgendwas im Zusammenhang mit getter oder setter passieren soll. Also z. B.:
Code:
class X {
   constructor() {
      var v = 100;
      this.getV = function() {
         return v;
      };
      var check = function(v) {
         if(isNaN(v))
            throw "value must be number";
         return v;
      };
      this.setV = function(_v) {
         v = check(_v);
      };
   }
   get v() {
      return this.getV();
   }
   set v(v) {
      this.setV(v);
   }
}
var x = new X();
x.v = 200;
alert(x.v);
check ist eine private Methode, v ist eine private Eigenschaft. Übergibt man v etwas, wird geprüft, ob das eine Ganzzahl ist.

Letztendlich will ich u. a. eine Vector-Klasse programmieren (für 3D). Dort soll es dann die privaten Eigenschaften x, y und z geben. Und jede dieser Eigenschaft muss dann eine Zahl sein (dann ist aber auch eine Fließkommazahl erlaubt). Darum diese eigene Methode check. Damit überprüfe ich dann alle 3 privaten Eigenschaften.
 
Zuletzt bearbeitet:
probiers mal so
Code:
class X {
   constructor() {
      var v = 100;
      var check = function(v) {
         if(isNaN(v))
            throw "value must be number";
         return v;
      };
      get v()
      {
        return v;
      }
      set v(_v)
      {
        v = check(_v);
      }
   }
}
var x = new X();
x.v = 200;
alert(x.v);
 
Funktioniert bei mir im Chrome leider nicht. Ich glaube, diese Variante hatte ich auch schon versucht.
 
weil das vermutlich icht geht, so
Code:
var X = (function()
{
  var v = 100;
  var check = function(v)
  {
    if(isNaN(v))
      throw "value must be number";
    return v;
  };
  class X {
    constructor() {
    }
    get v()
    {
      return v;
    }
    set v(_v)
    {
      v = check(_v);
    }
  }
  return X;
})();
var x = new X();
x.v = 200;
alert(x.v);

- - - Aktualisiert - - -

bei mir im Chrome
ich glaube Chrome ist der einzige browser der das überhaupt unterstützt.
 
Das schaut ziemlich abenteuerlich aus :d

Also ich glaube, ich habe jetzt meinen Programmierstil gefunden:
Code:
"use strict";
/**
 * Utility-Klasse, um für Klassen-Instanzen konstante Eigenschaften zu definieren.
 */
class Const {
   static create(_o, _name, _value) {
      Object.defineProperty(
         _o, 
         _name, {
            value: _value,
            writable: false
         }
      );
   }
}
class Triangle {
   constructor(_edges) {
      Const.create(this, "countEdges", 3);
      if(_edges.length != this.countEdges)
         throw "a triangle must consist of " + this.countEdges + " edges";
      
      var edges = [];
      for(let i = 0; i < this.countEdges; ++i) {
         if(!(_edges[i] instanceof Edge))
            throw "value must be of type Edge";
         edges[i] = _edges[i];
      }
      
      // Normale auf Dreieck:
      let v0 = edges[0].asVector().normalize();
      let v1 = edges[2].asVector(true).normalize();
      var normal = v0.cross(v1);
      
      // öffentliche Methoden:
      this.getEdge = function(i) {
         if(!Number.isInteger(i) || i < 0 || i >= this.countEdges)
            throw "index must be 0 to " + (this.countEdges - 1);
         return edges[i];
      };
      /**
       * @return string
       */
      this.toString = function() {
         return "{" + edges[0].toString() + " " + edges[1].toString() + " " + edges[2].toString() + "}";
      };
   }
}
class Edge {
   /**
    * @param Vertex _from
    * @param Vertex _to
    */
   constructor(_from, _to) {
      Const.create(this, "countVertices", 2);
      
      // private Methoden:
      var check = function(_vertex) {
         if(!(_vertex instanceof Vertex))
            throw "value must be of type Vertex";
         return _vertex;
      };
      
      var vertices = [];
      vertices[0] = check(_from);
      vertices[1] = check(_to);
      
      // öffentliche Methoden:
      this.getVertex = function(_i) {
         if(!Number.isInteger(_i) || _i < 0 || _i >= this.countVertices)
            throw "index must be 0 to " + (this.countVertices - 1);
         return vertices[_i];
      };
      /**
       * Kante als Vektor zurückgeben.
       * @param boolean _negate ob Vorzeichenwechsel
       */
      this.asVector = function(_negate) {
         if(_negate === undefined)
            _negate = false;
         else if(typeof(_negate) !== "boolean")
            throw "negate must be of type boolean";
         
         let v0 = vertices[0].w == 1 ? vertices[0] : vertices[0].homogenize();
         let v1 = vertices[1].w == 1 ? vertices[1] : vertices[1].homogenize();
         return _negate ? v0.minus(v1) : v1.minus(v0);
      };
      /**
       * @return string 
       */
      this.toString = function() {
         return "[" + vertices[0].toString() + " " + vertices[1].toString() + "]";
      };
   }
}
/**
 * Abstrakte Klasse für die Klassen Vector und Vertex.
 */
class AVector {
   constructor(_x, _y, _z) {
      // öffentliche Methoden:
      this.check = function(_v) {
         if(isNaN(_v))
            throw "value must be number";
         return _v;
      };

      // private Eigenschaften:
      var x = this.check(_x);
      var y = this.check(_y);
      var z = this.check(_z);
      
      // öffentliche Methoden:
      this.check = function(_v) {
         if(isNaN(_v))
            throw "value must be number";
         return _v;
      };
      this.getX = function() {
         return x;
      };
      this.getY = function() {
         return y;
      };
      this.getZ = function() {
         return z;
      };
      this.setX = function(_x) {
         x = this.check(_x);
      };
      this.setY = function(_y) {
         y = this.check(_y);
      };
      this.setZ = function(_z) {
         z = this.check(_z);
      };
   }
   // setter/getter:
   set x(_x) {
      this.setX(_x);
   }
   set y(_y) {
      this.setY(_y);
   }
   set z(_z) {
      this.setZ(_z);
   }
   get x() {
      return this.getX();
   }
   get y() {
      return this.getY();
   }
   get z() {
      return this.getZ();
   }
}
/**
 * Ein Vektor besteht aus den Komponenten x, y und z.
 * Ein Vektor ist eine Richtungsangabe.
 */
class Vector extends AVector {
   /**
    * @param number _x 
    * @param number _y 
    * @param number _z 
    */
   constructor(_x, _y, _z) {
      super(_x, _y, _z);
      /**
       * @return number 
       */
      this.length = function() { 
         return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
      };
      /**
       * @param boolean _self optionell, ob dieser Vektor selbst normalisiert werden soll
       * @return Vector 
       */
      this.normalize = function(_self) { 
         if(_self === undefined)
            _self = false;
         else if(typeof(_self) !== "boolean")
            throw "self must be of type boolean";
         
         let length = this.length();
         if(length == 0)
            throw "0-vector can´t be normalized";
         
         if(_self) {
            this.x /= length;
            this.y /= length;
            this.z /= length;
         }
         else return new Vector(
            this.x / length,
            this.y / length,
            this.z / length
         );
      };
      /**
       * Cross-Produkt zwischen 2 Vectoren.
       * @param Vector _other
       * @return Vector
       */
      this.cross = function(_other) { 
         if(!(_other instanceof Vector))
            throw "other must be of type Vector";
         
         return new Vector(
            this.y * _other.z - this.z * _other.y,
            this.z * _other.x - this.x * _other.z,
            this.x * _other.y - this.y * _other.x
         );
      };
      /**
       * @return string
       */
      this.toString = function() {
         return "(" + this.x + " " + this.y + " " + this.z + ")";
      };
   }
}
/**
 * Ein Vertex besteht aus den Komponenten x, y, z und w.
 * Ein Vertex ist eine Positionsangabe.
 */
class Vertex extends AVector {
   /**
    * @param number _x 
    * @param number _y 
    * @param number _z 
    * @param number _w
    */
   constructor(_x, _y, _z, _w) {
      super(_x, _y, _z);
      var w = _w === undefined ? 1 : this.check(_w); // darf die homogene Komponente auch negativ werden?
      
      // Normale auf Vertex vorbereiten:
      var normal = new Vector(0, 0, 0);
      
      // öffentliche Methoden:
      this.getW = function() {
         return w;
      };
      this.setW = function(_w) {
         w = this.check(_w);
      };
      /**
       * @param boolean _self optionell, ob dieser Vertex selbst homogenisiert werden soll
       * @return Vertex
       */
      this.homogenize = function(_self) { 
         if(_self === undefined)
            _self = false;
         else if(typeof(_self) !== "boolean")
            throw "self must be of type boolean";
         
         if(this.w == 0)
            throw "a vector with w = 0 can´t be homogenized";
         if(_self) {
            this.x /= this.w;
            this.y /= this.w;
            this.z /= this.w;
         }
         else return new Vertex(
            this.x / this.w,
            this.y / this.w,
            this.z / this.w
         );
      };
      /**
       * Ein Vertex minus einem Vertex ergibt einen Vektor.
       * @param Vertex _other
       * @return Vector
       */
      this.minus = function(_other) { 
         if(!(_other instanceof Vertex))
            throw "other must be of type Vertex";
         let v0 = this.w == 1 ? this : this.homogenize();
         let v1 = _other.w == 1 ? _other : _other.homogenize();
         return new Vector(
            v0.x - v1.x,
            v0.y - v1.y,
            v0.z - v1.z
         );
      };
      /**
       * @return string
       */
      this.toString = function() {
         return "(" + this.x + " " + this.y + " " + this.z + " " + this.w + ")";
      };
   }
   get w() {
      return this.getW();
   }
   set w(_w) {
      this.setW(_w);
   }
}

var v0 = new Vertex(1, 0, 0);
var v1 = new Vertex(0, 0, 0);
var v2 = new Vertex(0, 0, 1);
var e0 = new Edge(v0, v1);
var e1 = new Edge(v1, v2);
var e2 = new Edge(v2, v0);
var t = new Triangle([e0, e1, e2]);


alert(t.toString());
Ist der Stil OK?

Falls wer selbst damit herumexperimentieren will, hier auch gleich noch die html-Datei dazu:
HTML:
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>Title of the document</title>
   </head>
   <body>
      <script src="js.js"></script>
   </body>
</html>
 
Naja... eine Klasse nur für eine statische Methode ist nicht wirklich sinnvoll... entweder macht man da einfach nur eine Funktion oder, wenn man da ein paar Funktionen zusammenfassen will, man nimmt einfach nur ein Objekt.

Auch würde ich persönlich nicht mit klassischen get* und set* Methoden arbeiten, sondern direkt die getter und setter Funktionalität, die man mit Object.defineProperty() in jedem modernen Browser zur Verfügung hat, verwenden. Macht den Code, der dann die Eigenschaft verwendet, in meinen Augen um einiges lesbarer.
Code:
function Auto(){
	var reifen = 4;
	Object.defineProperty(
		this,
		"reifen",
		{
			get: function(){return reifen;},
			set: function(newReifen){
				if ((typeof newReifen) !== "number"){
					throw new TypeError("Reifen falsch.");
				}
				else {
					reifen = newReifen;
				}
			}
		}
	);
}

var a = new Auto();
a.reifen = 2;
console.log(a.reifen);
a.reifen = "hallo";
 
Auch würde ich persönlich nicht mit klassischen get* und set* Methoden arbeiten
das sehe ich genau anders herum. schon weil es in c++ überhaupt nicht anders geht und ich es damit so gewohnt bin. aber ich denke es spricht auch einiges für get-/set-methoden. du siehst z.b sofort, dass du über eine funktion auf eine variable zugreifst. über getter/setter-funktionen kannst du von außen nicht unterscheiden, ob es sich um einen nicht gewünschten direkten variablenzugriff oder eine öffentliche schnittstelle handelt.
(außerdem kannst du eine get-/set-funktion besser suchen - aber das will ich mal nicht mit als vorteil zählen)
Was ist jetzt der vorteil von getter/setter-funktionen? ich sehe keinen.
den einzigen punkt, den ich sehen würde, ist hier, ähnlich wie im IDL mit propget, in einer öffentlichen schnittstelle den endanwender nicht zu überfordern, der dann gerne als geistig minderbemittelt angesehen wird und mit x.getY() nicht umgehen kann aber x.y schon kennt. aber eine öffentlichen schnittstelle für dummys dürfte man recht selten entwickeln, und selbst dann sollte man vielleicht darüber nachdenken beim anwender grundkentnisse in OOP vorrauszusetzten.
 
Was ist jetzt der vorteil von getter/setter-funktionen?
Wenn man sich Algorithmen anschaut, sind das immer ganz normale Rechenoperationen. Wenn man mit getter/setter-Funktionen arbeitet, muss man diese Algorithmen mehr oder weniger nur 1:1 abtippen, man muss sich keine Gedanken darüber machen, wo ein set, ein get, oder wo man irgendwas irgendwie anders verschachteln muss. Ich find das so ganz bequem. Es bleibt auch lesbarer :)
 
Wenn man sich Algorithmen anschaut, sind das immer ganz normale Rechenoperationen. Wenn man mit getter/setter-Funktionen arbeitet, muss man diese Algorithmen mehr oder weniger nur 1:1 abtippen
selbst wenn du deinen algorithmus irgendwo als vordruck haben solltest, musst du ihn sowieso um den objektzugriff ergänzen.
 
das sehe ich genau anders herum.
Deswegen hab' ich "persönlich" geschrieben. Wusste schon, dass du da nicht mit mir einer Meinung bist... und wollte auch keine Diskussion darüber anfangen, sondern nur die Möglichkeit in den Raum stellen.
ich es damit so gewohnt bin
Ich bin es anders gewohnt...
ob es sich um einen nicht gewünschten direkten variablenzugriff oder eine öffentliche schnittstelle handelt.
Als "Nutzer" der Klasse solltest du dich immer an die Dokumentation halten. Da muss so etwas drin stehen. Auch bei einem Funktionsaufruf weißt du nicht, ob ein Aufruf dieser gewünscht ist oder nicht.
Was ist jetzt der vorteil von getter/setter-funktionen? ich sehe keinen.
Ich finde es einfacher zu schreiben und zu lesen.
Außerdem gibt es Programmiersprachen, bei denen man nicht alles direkt mit Funktionen machen kann (z.B. in MATLAB kann man direkt nach einem Funktionsaufruf keinen Arrayzugriff ausführen - man muss über eine Variable gehen, die den Rückgabewert der Funktion speichert).
aber eine öffentlichen schnittstelle für dummys dürfte man recht selten entwickeln
Da hab' ich andere Erfahrung gemacht. Ich würde jetzt zwar nicht von "Dummies" reden, aber wenig erfahrene Programmierer (und v.a. solche, die eigentlich gar keine sein wollen, aber trotzdem etwas programmieren wollen/sollen) haben schon mit dem Grundkonzept von OOP Probleme.

Und ich bin nicht der Meinung, dass Zugriffsfunktionen zu
grundkentnisse in OOP
gehören. Nur weil Java, C++, etc. keine elegante Lösung für das Problem haben...
 
Als "Nutzer" der Klasse solltest du dich immer an die Dokumentation halten.
das "sollte" so sein

Da muss so etwas drin stehen.
wenn, aus welchen gründen auch immer, ein funktionsaufruf nicht erlaubt, aber die funktion trotzdem zugreifbar ist, sollte die funktion in der dokumentation auf keinen fall mit "bitte diese funktion nicht aufrufen" erwäht werden. das führt mit sicherheit zum aufruf

Auch bei einem Funktionsaufruf weißt du nicht, ob ein Aufruf dieser gewünscht ist oder nicht.
doch, eine funktion, deren aufruf nicht gewünscht ist, ist nicht in der schnittstelle enthalten/nicht zugreifbar/private

Da hab' ich andere Erfahrung gemacht. Ich würde jetzt zwar nicht von "Dummies" reden, aber wenig erfahrene Programmierer (und v.a. solche, die eigentlich gar keine sein wollen, aber trotzdem etwas programmieren wollen/sollen) haben schon mit dem Grundkonzept von OOP Probleme.
dann müssen sie das lernen

Und ich bin nicht der Meinung, dass Zugriffsfunktionen zu grundkentnisse in OOP gehören.
zugriffsfunktionen im sinne von "greife nie direkt auf eine variable zu, sondern immer über eine funktion".
also auch getter/setter erfüllen diese regel der oop, nur kann man das von außen nicht erkennen.

Deswegen hab' ich "persönlich" geschrieben.
und ich habe geschrieben
das sehe ich genau anders herum.
da kommt zwar das wort "persönlich" nicht vor, aber es sollte als meinung erkennbar sein.

Wusste schon, dass du da nicht mit mir einer Meinung bist... und wollte auch keine Diskussion darüber anfangen
wenn du nicht diskutieren willst und dich schon wieder auf den schlips getreten fühlst(so habe ich das herausgelesen), weil ich eine andere meinung habe als du, dann lass es sein. allerdings frage ich mich dann, warum du dich ausgerechnet in einem forum herumtreibst.

sondern nur die Möglichkeit in den Raum stellen.
ja, hab ich ja nichts gegen(und auch m1au hat ja schon getter/setter in der außenschnittstelle gehabt), ich hab nur nach den gründen gefragt, weswegen du "persönlich" nicht mit klassischen get und set methoden arbeiten würdest und meine gründe dargelegt, warum ich das gerade machen würde.
 
Zuletzt bearbeitet:
Fühle mich nicht auf den Schlips getreten. Wir hatten nur diese Diskussion schon einmal.

dann müssen sie das lernen
Ich glaube, wir reden hier von einem komplett unterschiedlichem Klientel...
und auch m1au hat ja schon getter/setter in der außenschnittstelle gehabt
Wo? Ich finde sie gerade nicht...
ch hab nur nach den gründen gefragt, weswegen du "persönlich" nicht mit klassischen get und set methoden arbeiten würdest
Wie ich oben schon geschrieben hab': ich bin gewohnt, sowas über "interne" setter und getter zu machen, und finde sie schöner. Außerdem ist das DOM ja auch schon voll davon (z.B. innerHTML) - somit hätten wir bei JS im Browser auch noch ein Konsistenzargument...
 
Zurück
Oben