19 Stimmen

Javascript automatische Getter/Setter (John Resig Buch)

Ich lese "Pro Javascript Techniques" von John Resig und bin mit einem Beispiel verwirrt. Dies ist der Code:

// Erstellt ein neues Benutzerobjekt, das ein Objekt von Eigenschaften akzeptiert
function User( properties ) {
  // Iteriere über die Eigenschaften des Objekts und überprüfe,
  // dass es ordnungsgemäß abgeschirmt ist (wie zuvor besprochen)
  for ( var i in properties ) { (function(){
  // Erstellt ein neues Getter für die Eigenschaft
  this[ "get" + i ] = function() {
    return properties[i];
  };
  // Erstellt ein neues Setter für die Eigenschaft
  this[ "set" + i ] = function(val) {
    properties[i] = val;
  };
})(); }
}

// Erstellt eine neue Benutzerobjektinstanz und gibt ein Objekt von
// Eigenschaften mit, um es zu initialisieren
var user = new User({
  name: "Bob",
  age: 44
});

// Beachte nur, dass die Eigenschaft 'name' nicht existiert, da sie privat ist
// innerhalb des Eigenschaftenobjekts
alert( user.name == null );

// Jedoch können wir auf ihren Wert über die neue getname()
// Methode zugreifen, die dynamisch generiert wurde
alert( user.getname() == "Bob" );

// Schließlich können wir sehen, dass es möglich ist, das Alter zu setzen und abzurufen
// mithilfe der neu generierten Funktionen
user.setage( 22 );
alert( user.getage() == 22 );

Jetzt wirft das Ausführen davon auf der Firebug-Konsole (auf FF3) einen Fehler, dass user.getname() keine Funktion ist. Ich habe versucht, das zu machen:

var other = User
other()
window.getname() --> das funktioniert!

Und es hat funktioniert!

Irgendwelche Ideen warum? Vielen Dank an alle!

PS: Ich empfehle dieses Buch nachdrücklich.

EDIT:

das hier ausführen:

var me = this;

scheint etwas besser zu funktionieren, aber beim Ausführen von "getname()" gibt es '44' zurück (die zweite Eigenschaft)...

außerdem finde ich es seltsam, dass es auf dem window-Objekt ohne Änderung funktioniert hat...

und eine dritte Frage, was ist der Unterschied zwischen PEZ Lösung und dem Original? (er verwendet keine anonyme Funktion)

Danke an alle für das Feedback! +1

5voto

Andreas Grech Punkte 102197

Ich finde es am besten, das new-Schlüsselwort überhaupt nicht zu verwenden, wenn man in JavaScript arbeitet.

Dies liegt daran, dass wenn Sie dann das Objekt ohne Verwendung des new-Schlüsselworts instanziieren (z.B. var user = User()) versehentlich, *sehr schlimme Dinge passieren werden...* der Grund dafür ist, dass in der Funktion (wenn ohne das new-Schlüsselwort instanziiert), das this auf das globale Objekt, d.h. das window, verweisen wird...

Ich schlage daher eine bessere Möglichkeit vor, wie man klassenähnliche Objekte verwendet.

Betrachten Sie das folgende Beispiel:

var user = function (props) {
    var pObject = {};
    for (p in props) {
        (function (pc) {
            pObject['set' + pc] = function (v) {
                props[pc] = v;
                return pObject;
            }
            pObject['get' + pc] = function () {
                return props[pc];
            }
        })(p);
    }
    return pObject;
}

In dem obigen Beispiel erstelle ich ein neues Objekt innerhalb der Funktion und füge dann Getter und Setter zu diesem neu erstellten Objekt hinzu.

Zuletzt gebe ich dieses neu erstellte Objekt zurück. Beachten Sie, dass das this-Schlüsselwort nirgendwo verwendet wird

Dann würde ich folgendes tun, um einen user "zu instanziieren":

var john = user({name : 'Andreas', age : 21});
john.getname(); // gibt 'Andreas' zurück
john.setage(19).getage(); // gibt 19 zurück

Der beste Weg, um nicht in Fallen zu tappen, besteht darin, sie überhaupt nicht zu schaffen... In dem obigen Beispiel vermeide ich die Falle des new-Schlüsselworts (wie ich sagte, wenn das new-Schlüsselwort nicht verwendet wird, wenn es verwendet werden sollte, werden schlechte Dinge passieren), indem ich überhaupt kein new verwende.

4voto

PEZ Punkte 16398

BEARBEITEN: Jetzt, indem ich Jasons Antwort anpasse, funktioniert es:

Wir müssen eine Closure für die Werte erstellen. Hier ist ein Weg:

function bindAccessors(o, property, value) {
  var _value = value;
  o["get" + property] = function() {
    return _value;
  };
  o["set" + property] = function(v) {
    _value = v;
  };
}

Dann sieht der Benutzerkonstruktor so aus:

function User( properties ) {
  for (var i in properties ) {
    bindAccessors(this, i, properties[i]);
  }
}

3voto

Jason S Punkte 178087

Du möchtest wahrscheinlich etwas wie dies, was lesbarer ist: (Closures sind leicht zu lernen, wenn du etwas Übung bekommst)

function User( properties ) {
  // Hilfsfunktion zur Erstellung von Closures basierend auf übergebenen Argumenten:
  var bindGetterSetter = function(obj,p,properties)
  {
    obj["get"+p]=function() { return properties[p]; }
    obj["set"+p]=function(val) { properties[p]=val; return this; }
  };
  for (var p in properties)
    bindGetterSetter(this, p, properties);
}

Ich habe auch "return this;" hinzugefügt, damit du Folgendes tun kannst:

u=new User({a: 1, b:77, c:48});
u.seta(3).setb(20).setc(400)

3voto

Pablo Fernandez Punkte 98441

Ich habe diesen Beitrag mit dem alleinigen Zweck begonnen, herauszufinden, warum diese Dinge passiert sind, und das habe ich schließlich getan. Für den Fall, dass es jemanden gibt, der an den "Warums" interessiert ist, hier sind sie:

Warum ändert sich 'this' innerhalb der anonymen Funktion?

Eine neue Funktion, auch wenn sie anonym ist, die innerhalb eines Objekts oder einer anderen Funktion deklariert wird, ÄNDERT IMMER DEN UMFANG, in diesem Fall zurück zum globalen Bereich (window)

Lösung: Alles im Beitrag aufgeführt, ich denke, am klarsten ist es, die anonyme Funktion mit .call(this) auszuführen

Warum gibt getname() immer das Alter zurück?

Während die anonyme Funktion sofort ausgeführt wird, werden die Getter/Setter erst beim ersten Mal ausgeführt, wenn sie aufgerufen werden. Zu diesem Zeitpunkt wird der Wert von i immer der letzte sein, weil er bereits für alle Eigenschaften iteriert hat ... und wird immer properties[i] zurückgeben, was der letzte Wert ist, in diesem Fall das Alter.

Lösung: speichern Sie den Wert von i in einer Variablen wie diese

 for ( i in properties ) { (function(){ 
  var j = i
  //verwenden Sie ab jetzt properties[j]

Das ist im Grunde genommen alles, wenn ich in irgendetwas, was ich gesagt habe, falsch liege, bitte korrigieren Sie mich, da ich versuche, dies zu lernen...

Nochmals vielen Dank.

2voto

J Cooper Punkte 16641

Wie im OP geschrieben, bezieht sich this in der Schleife nicht wie es sollte auf das Benutzerobjekt. Wenn Sie diese Variable außerhalb der Schleife erfassen, können Sie sie funktionieren lassen:

function User( properties ) {
  // Iteriere durch die Eigenschaften des Objekts und stelle sicher, dass es ordnungsgemäß abgegrenzt ist (wie zuvor besprochen)
 var me = this;
 for ( i in properties ) { (function(){
  // Erstelle einen neuen Getter für die Eigenschaft
  me[ "get" + i ] = function() {
    return properties[i];
  };
  // Erstelle einen neuen Setter für die Eigenschaft
  me[ "set" + i ] = function(val) {
    properties[i] = val;
  };
 // usw.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X