2 Stimmen

setter/getter funktioniert nicht bei Zahlenliteralen

Ich dachte, es würde Spaß machen, meine Null-Padding-Erweiterung des Number.prototype in ein echtes Getter/Setter-Muster umzuschreiben. Nicht sehr schwierig. Am Ende habe ich diesen Code erhalten ( addSetter y addGetter sind nur Wrapper-Funktionen, die prototype.__defineGetter__ / __defineSetter__ .

Number.addSetter('leftPad0',
  function(v){
    var  len = (String(v).length - String(this).length)+1;
    this._leftPad0 = new Array(len).join('0')+this;
  }
);

Number.addGetter('leftPad0',
  function(){
    return this._leftPad0;
  }
);

Funktioniert gut bei echten Zahlenobjekten:

var a = new Number(977);
a.leftPad0 = 10000;
alert('a => '+a.leftPad0); // a => 00977

Aber nicht für Zahlenliterale:

var b = 977;
b.leftPad0 = 10000;
alert('b => '+b.leftPad0); // b => undefined

Erreicht B also nicht den Einrichter? Oder wenn es den Setzer erreicht, ist es dann nicht eine Zahl?

Ich protokollierte dies in der Konsole innerhalb der Setter-Funktion:

this.constructor === Number // true
this instanceof Number //true

Oder wird der Getter nicht erreicht, oder wenn es erreicht wird, würde das Literal nicht eine Instanz von Number sein? Ich habe dasselbe innerhalb des Getters protokolliert. Alles gut und auch wahr.

Was kann also der Grund dafür sein, dass wir dieses Muster nicht mit einem Zahlenliteral verwenden können? Oder habe ich etwas übersehen?

Hinweis: Dieses Problem tritt nicht auf, wenn ich diese Prototyp-Erweiterung ('monkey patch') verwende:

Number.prototype.leftPad = function(base){
  var  len = (String(base).length - String(this).length)+1;
  return new Array(len).join('0')+this;
}

alert( (977).leftPad(10000) ); // 00977

[ bearbeiten ] Ich frage mich immer noch, ob wir dies als Fehler bezeichnen müssen, oder ob es dem/a Standard entspricht. Wie auch immer, ich habe jetzt mein eigenes Objekt dafür entwickelt:

function NumPL(val,pval,chr){
   if (!(this instanceof NumPL)){
      return new NumPL(val,pval,chr);
   }
   this._value = new Number(val||0);
   this._padValue = pval || 10;
   this.chr = chr || '0';
}

NumPL.prototype = {
    get value(){
        return this._value;
    },
    set padValue(v) {
        this._padValue = v%10 === 0 ? v : 10;
    },
    set value(v) {
        this._value = v;
    },
    get padLeft(){
       var  len = (String(this._padValue).length - 
                   String(this._value).length)+1;
       return new Array(len).join(this.chr)+this._value;
    }
}
// Usage
var a = NumPL(977,10000);
alert(a.padLeft); //=> 00977
// or a real world example
var dat = new Date,
    datshort = [dat.getFullYear(),
                NumPL(dat.getMonth()+1).padLeft,
                NumPL(dat.getDate()).padLeft]
               .join('/');
 alert(datshort); //=> 2011/05/19

4voto

mu is too short Punkte 411765

Eine wörtliche Zahl ist keine Number :

typeof 3
// "number"

typeof new Number(3)
// "object"

Es gibt also keinen Prototyp, der für numerische Literale geändert werden muss.

Wenn Sie jedoch versuchen, eine Eigenschaft für ein numerisches Literal festzulegen, sieht es so aus, als ob das Literal zuerst in ein Number-Objekt eingeschlossen wird. Dann wird der Setter für dieses Objekt aufgerufen und this wird ein Objekt innerhalb der Setter-Funktion sein. Und dann wird das Literal ausgepackt, wenn der Setter zurückkehrt, und dieses Auspacken lässt die Eigenschaft (die auf dem Objekt-Wrapper eingestellt wurde) zurück.

Number.prototype.__defineSetter__('leftPad0',
    function(v) {
        alert('In setter: ' + v + ' ' + (this instanceof Number));
        var len = (String(v).length - String(this).length) + 1;
        this._leftPad0 = new Array(len).join('0') + this;
    }
);

var a = new Number(977);
a.leftPad0 = 10000;
alert('a => ' + a._leftPad0);

var b = 977;
b.leftPad0 = 10000;
alert('b => ' + b._leftPad0);

http://jsfiddle.net/ambiguous/H77qk/2/

Ich erhalte vier Warnmeldungen in verschiedenen Browsern.

Es tut mir leid, aber ich habe keine verbindliche Referenz für dieses Verhalten, nur empirische Beweise.

2voto

Demian Brecht Punkte 20756

var b = 9; bedeutet, dass b ist ein Verweis auf einen primitiven Typ, nicht auf ein Objekt des Typs Number .

var b = new Number(9) erzeugt ein Objekt vom Typ Number die wird enthalten die Funktion, die der Number Prototyp, nicht ein primitiver Zahlentyp.

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